IIS7 Substitui customErrors ao definir Response.StatusCode?

98

Tendo um problema estranho aqui. Todo mundo sabe que se você usar a customErrorsseção web.config para fazer uma página de erro personalizada, você deve definir seu Response.StatusCodepara o que for apropriado. Por exemplo, se eu fizer uma página 404 personalizada e chamá-la de 404.aspx, poderia inserir <% Response.StatusCode = 404 %>o conteúdo para que tenha um cabeçalho de status 404 verdadeiro.

Me segue até agora? Boa. Agora tente fazer isso no IIS7. Eu não consigo fazer funcionar, ponto final. Se Response.StatusCodeestiver definido na página de erro personalizada, o IIS7 parece substituir completamente a página de erro personalizada e mostra sua própria página de status (se houver uma configurada).

Alguém mais viu esse comportamento e talvez saiba como contorná-lo? Estava funcionando no IIS6, então não sei por que as coisas mudaram.

Nota: Este não é o mesmo que o problema no ASP.NET Custom 404 Retornando 200 OK em vez de 404 Not Found

Nicholas
fonte
Bobby, eu realmente encontrei essa pergunta e tentei, mas não resolveu o problema. Mas obrigado.
Nicholas
Eu gostaria de comentar que esse problema também ocorre ao mudar de tubo clássico para tubo integrado. Usei a solução @PavelChuchuva (a solução @RickStrahl também funciona). Eu estou supondo que o "passthrough" no Classic é automático, no Integrated leva a manipulação da página de erro global do servidor ..
sonjz

Respostas:

116

Defina existingResponse como PassThrough na seção system.webServer / httpErrors:

  <system.webServer>
    <httpErrors existingResponse="PassThrough" />
  </system.webServer>

O valor padrão da propriedade existingResponse é Auto:

Auto diz ao módulo de erro personalizado para fazer a coisa certa . O texto de erro real visto pelos clientes será afetado dependendo do valor de fExperimenteSkipCustomErrors retornado na IHttpResponse::GetStatuschamada. Quando fExperimenteSkipCustomErrors é definido como verdadeiro, o módulo de erro personalizado permitirá que a resposta passe, mas se for definido como falso, o módulo de erros personalizado substituirá o texto por seu próprio texto.

Mais informações: O que esperar do módulo de erro personalizado IIS7

Pavel Chuchuva
fonte
3
Observe que definir existingResponse para PassThrough pode causar algum efeito colateral. Por favor, domine o link fornecido por Pavel antes de qualquer alteração.
Lex Li
É <httpErrors existingResponse="PassThrough" />equivalente Response.TrySkipIisCustomErrorsou se comportam de maneira diferente?
Asbjørn Ulsberg
1
@sbjornu Eles alcançam a mesma coisa, mas com Response.TrySkipIisCustomErrorsvocê obtém um melhor controle quando exibir os erros personalizados do IIS.
Pavel Chuchuva
obrigado, vi muitas informações sobre response.tryskipiiscustomerrors, mas não tanto sobre a resposta existente.
HBCondo
Resolvi um problema com as páginas de erro personalizadas que não funcionavam em meu host executando IIS7 simplesmente definindo existingResponse = "Auto", o que foi muito surpreendente, pois o artigo referenciado afirma que é o padrão. Claramente não é ... ou minha empresa de hospedagem definiu o padrão errado em outro lugar, eu suponho. De qualquer forma, espero que alguém economize algumas horas: \
Eric Sassaman
80

A maneira mais fácil de tornar o comportamento consistente é limpar o erro e usar Response.TrySkipIisCustomErrors e defini-lo como verdadeiro. Isso substituirá o tratamento da página de erro global IIS de dentro da sua página ou o manipulador de erro global em Application_Error.

Server.ClearError();
Response.TrySkipIisCustomErrors = true;

Normalmente, você deve fazer isso em seu manipulador Application_Error que trata todos os erros que seus manipuladores de erro do aplicativo não estão detectando.

Informações mais detalhadas podem ser encontradas nesta postagem do blog: http://www.west-wind.com/weblog/posts/745738.aspx

Rick Strahl
fonte
2
Isso também não funciona para mim (IIS8), e o conselho não parece corresponder ao OP (presumindo que eu esteja lendo corretamente). Eu quero o customErrorconfigurado no Web.config para gatilho. Com Response.TrySkipIisCustomErrors = trueeu obtenho o mesmo comportamento: A página de erro gerado pelo servidor feia é exibida. Com ele definido como falsenada acontece - uma janela do navegador em branco.
Shawn South
Funcionou bem para mim! Embora a configuração mencionada por Pavel Chuchuva em sua resposta também tenha funcionado, ela teve alguns efeitos colaterais que causaram outros problemas. Essa configuração me permite ignorar a substituição de erro do IIS no cenário específico que eu queria, enquanto deixa o comportamento intacto para todo o resto.
Kevin Tighe
Funcionou bem no Azure para mim. Cabeçalhos do servidorServer:Microsoft-IIS/8.5 X-AspNet-Version:4.0.30319 X-AspNetMvc-Version:5.2 X-Powered-By:ASP.NET
oxfn
Ainda acho que preciso configurar customErrors mode="Off"para que isso funcione. Se eu fizer isso, o httpErrors existingResponse = "Auto" (o padrão) funcionará corretamente para mim quando eu usar o código nesta resposta.
AaronLS de
11

Resolvido: Acontece que os "Erros detalhados" precisam estar ativados para que o IIS7 "passe" qualquer página de erro que você possa ter. Veja http://forums.iis.net/t/1146653.aspx

Nicholas
fonte
1
Embora esta tenha sido marcada como a resposta, acho que vale a pena ler outras respostas para obter mais informações sobre o assunto.
Lex Li
Também pode ser bom remover. HandleErrorAttribute em FilterConfig
Por G de
4

Não tenho certeza se isso é semelhante em natureza ou não, mas resolvi um problema que parece semelhante à primeira vista e foi assim que resolvi.

Em primeiro lugar, o valor padrão para existingResponse (Auto) foi a resposta correta no meu caso, já que tenho um 404, 400 e 500 customizado (eu poderia criar outros, mas esses três serão suficientes para o que estou fazendo). Aqui estão as seções relevantes que me ajudaram.

De web.config:

<customErrors mode="Off" />

E

<httpErrors errorMode="Custom" existingResponse="Auto" defaultResponseMode="ExecuteURL">
  <clear />
  <error statusCode="404" path="/errors/404.aspx" responseMode="ExecuteURL" />
  <error statusCode="500" path="/errors/500.aspx" responseMode="ExecuteURL" />
  <error statusCode="400" path="/errors/400.aspx" responseMode="ExecuteURL" />
</httpErrors>

A partir daí, adicionei isso a Application_Error em global.asax:

    Response.TrySkipIisCustomErrors = True

Em cada uma das minhas páginas de erro personalizadas, tive que incluir o código de status de resposta correto. No meu caso, estou usando um 404 personalizado para enviar usuários a diferentes seções do meu site, então não quero um código de status 404 retornado, a menos que seja realmente uma página inativa.

De qualquer forma, foi assim que eu fiz. Espero que ajude alguém.

SEFL
fonte
3

Este problema tem sido uma grande dor de cabeça. Nenhuma das sugestões mencionadas anteriormente sozinhas resolveu isso para mim, então estou incluindo minha solução. Para registro, nosso ambiente / plataforma usa:

  • .NET Framework 4
  • MVC 3
  • IIS8 (estação de trabalho) e IIS7 (servidor web)

Especificamente, eu estava tentando obter uma resposta HTTP 404 que redirecionaria o usuário para nossa página 404 personalizada (por meio das configurações Web.config).

Primeiro, meu código teve que lançar um HttpException. Retornar a NotFoundResultdo controlador não atingiu os resultados que eu queria.

throw new HttpException(404, "There is no class with that subject");

Então eu tive que configure tanto o customErrorse httpErrornós no Web.config.

<customErrors mode="On" defaultRedirect="/classes/Error.aspx">
  <error statusCode="404" redirect="/classes/404.html" />
</customErrors>

...

<httpErrors errorMode="Custom" existingResponse="Auto" defaultResponseMode="ExecuteURL">
  <clear />
  <error statusCode="404" path="/classes/404.aspx" responseMode="ExecuteURL" />
</httpErrors>

Note que eu deixei o existingResponsecomo Auto, o que é diferente do que o @sefl solução fornecida.

As customErrorsconfigurações pareciam ser necessárias para lidar com minhas jogadas explicitamente HttpException, enquanto o httpErrorsnó manipulava URLs que estavam fora dos padrões de rota especificados em Globals.asax.cs.

PS Com essas configurações, eu não preciso definir Response.TrySkipIisCustomErrors

Shawn South
fonte
2

TrySkipIisCustomErrorsé apenas parte de um quebra-cabeça. Se você usa páginas de erro personalizadas, mas também deseja entregar algum conteúdo RESTful com base nos status 4xx, você tem um problema. Definir httpErrors.existingResponse do web.config como "Auto" não funciona, porque .net parece sempre entregar algum conteúdo de página ao IIS, portanto, usar "Auto" faz com que todas (ou pelo menos algumas) Páginas de erro personalizadas não sejam usadas. Usar "Substituir" também não funcionará, porque a resposta conterá seu código de status http, mas seu conteúdo estará vazio ou preenchido com uma página de erro personalizada. E o "PassThrough" na verdade desativa o CEP, então ele não pode ser usado.

Portanto, se você quiser ignorar o CEP em alguns casos (por ignorar, quero dizer retornar o status 4xx com algum conteúdo), você precisará de uma etapa adicional: limpe o erro:

void Application_Error(object sender, EventArgs e)
{
    var httpException = Context.Server.GetLastError() as HttpException;
    var statusCode = httpException != null ? httpException.GetHttpCode() : (int)HttpStatusCode.InternalServerError;

    Context.Server.ClearError();
    Context.Response.StatusCode = statusCode;
}

Então, se você quiser usar a resposta REST (ou seja, 400 - Bad Request) e enviar algum conteúdo com ela, você só precisará definir TrySkipIisCustomErrorsalgum lugar em ação e definirexistingResponse inválida como "Auto" na seção httpErrors em web.config. Agora:

  • quando não há erro (a ação retorna 4xx ou 5xx) e algum conteúdo é retornado o CEP não é utilizado e o conteúdo é passado para o cliente;
  • quando há um erro (uma exceção é lançada), o conteúdo retornado pelos manipuladores de erro é removido, então o CEP é usado.

Se você quiser retornar o status com o conteúdo vazio de sua ação, ele será tratado como uma resposta vazia e o CEP será mostrado, portanto, há espaço para melhorar este código.

Łukasƨ Fronczyk
fonte
0

Por padrão, o IIS 7 usa mensagens de erro personalizadas detalhadas, portanto, presumo que Response.StatusCode será igual a 404.XX em vez de apenas 404.

Você pode configurar o IIS7 para usar os códigos de mensagem de erro mais simples ou modificar o código que trata das mensagens de erro mais detalhadas que o IIS7 oferece.

Mais informações disponíveis aqui: http://blogs.iis.net/rakkimk/archive/2008/10/03/iis7-enabling-custom-error-pages.aspx

Uma investigação mais aprofundada revelou que entendi errado - mensagens detalhadas não são por padrão, mas talvez tenham sido ativadas em sua caixa se você estiver vendo as diferentes mensagens de erro que mencionou.

nullnvoid
fonte
Response.StatusCode é um inteiro, então não vejo uma maneira de definir um código mais específico do que apenas "404". Eu tenho o IIS7 configurado para usar / mostrar páginas de erro personalizadas, como seu URL indica.
Nicholas
Hmmm ... Infelizmente não posso testar no momento porque não estou no meu pc doméstico. Se você não tiver uma solução até então - eu darei uma olhada esta noite.
nullnvoid