ASP.NET MVC自定义错误页面无法显示某些400错误

11

我正在处理一个新的ASP.NET MVC应用程序的自定义错误页面管理问题,这很有趣。

这个问题是这样的:
- 如果我调用URL(无论哪个),并在URL结尾处使用“坏”参数,例如..../c<,则应用程序将按照web.config中的指示显示正确的服务器错误页面;
- 如果我将URL更改为更恶劣的URL,例如.../<c(看起来更像HTML标记),那么浏览器中不再显示服务器错误页面,而是得到一个简单的YSOD和一条消息,例如An exception occurred while processing your request. Additionally, another exception occurred while executing the custom error page for the first exception. The request has been terminated.

根据ELMAH的记录,两个请求都以400状态码结束,并显示以下信息:
- 对于第一个请求:System.Web.HttpException (0x80004005): A potentially dangerous Request.Path value was detected from the client (<). at System.Web.HttpRequest.ValidateInputIfRequiredByConfig() at System.Web.HttpApplication.PipelineStepManager.ValidateHelper(HttpContext context)
- 对于第二个请求:System.Web.HttpException (0x80004005): A potentially dangerous Request.Path value was detected from the client (<). at System.Web.HttpRequest.ValidateInputIfRequiredByConfig() at System.Web.HttpApplication.PipelineStepManager.ValidateHelper(HttpContext context)

因此,两个错误都相同,状态码也相同,但对于其中一个错误,自定义错误页面不再显示。我还在全局.asax文件中以调试模式检查了protected void Application_Error(object sender, EventArgs e)中的Server.GetLastError(),结果两个错误都是一样的,没有什么不同。

在web.config中,我的<customErrors>标记如下所示:

<customErrors mode="On" defaultRedirect="/ServerError.aspx" redirectMode="ResponseRewrite">

<error statusCode="500" redirect="/ServerError.aspx" /> <error statusCode="404" redirect="/PageNotFound.aspx" /> </customErrors>
请问为什么这两种情况的行为不同?
非常感谢您的时间。

你在哪个服务器上托管?Cassini?IIS6?IIS7+? - Iain Galloway
IIS 8.5(Windows 8.1)以及Azure网站。 - Edi
1个回答

19

在处理IIS 7+的错误处理时,存在大量错误信息和/或过时的解决方案。主要需要了解以下几点:

  • .NET 4.0对ASP.NET的请求验证进行了破坏性更改。
  • IIS 7+引入了一种新的处理自定义错误页面的方法。

大多数人使用混合解决方案,涉及customErrorshttpErrorsApplication_Error处理程序,并经常在httpRuntime属性上设置requestValidationMode="2.0"和/或完全禁用请求验证!这使得使用其他人的解决方案变得非常困难,因为所有这些都可能影响行为。我快速搜索了一下,发现有几个半重复的问题没有被解答,很可能是因为这个原因。

这两个错误产生不同行为的原因在于它们发生在请求管道的不同阶段。在你的web.config文件中,customErrors节点与应用程序内部的错误进行交互,而请求验证则发生在应用程序外部。IIS在请求到达应用程序代码之前拒绝了危险请求,因此你的customErrors替换不会发生。
那么我们该如何解决呢?
理想情况下,你希望解决方案的移动部分尽可能少。IIS7提供了一种新的错误页面替代方法,可以在IIS级别而不是应用程序级别指定-httpErrors节点。这使我们可以在一个地方捕获所有错误:-
<configuration>
  ...
  <system.webServer>
    ...
    <httpErrors errorMode="Custom" existingResponse="Replace">
      <clear />
      <error statusCode="400" responseMode="ExecuteURL" path="/ServerError.aspx"/>
      <error statusCode="403" responseMode="ExecuteURL" path="/ServerError.aspx" />
      <error statusCode="404" responseMode="ExecuteURL" path="/PageNotFound.aspx" />
      <error statusCode="500" responseMode="ExecuteURL" path="/ServerError.aspx" />
    </httpErrors>
    ...
  </system.webServer>
  ...
</configuration>

如果您关心SEO(而且您应该!),您仍然需要确保您的控制器/页面设置适当的状态码:-
this.Response.StatusCode = 500; // etc.

您应该完全删除自定义错误节点customErrors,这通常用于向后兼容。您还应确保在httpRuntime节点上未设置requestValidationMode
这样可以捕获大多数错误(显然不包括解析web.config中的错误!)。
相关链接:ASP.NET MVC自定义错误 MSDN文档:http://www.iis.net/configreference/system.webserver/httperrors 请注意:在您的情况下,如果您想在httpErrors节点上设置defaultPath,由于ApplicationHost.config设置,您将遇到锁定违规问题。您可以像我一样为您关心的错误代码单独设置path,或者查看如何解锁节点:

我的直觉是,在像Azure App Service / Azure Web Sites这样的低控制环境中,这会带来更多的麻烦而不值得。您最好为单个状态代码设置路径。

我在github上放了一个完整的使用httpErrors自定义错误页面的工作示例。您也可以在Azure Web Sites上实时查看它


迄今为止,这是我多年来看到的最详细和完美的回复。非常感谢!!!它完美地工作了!!! - Edi
你最好将其作为一个单独的问题发布,并提供更多信息。我知道 httpModules 中的错误可能会导致自定义错误出现问题,但在我能够缩小范围之前,我需要更多的信息。 - Iain Galloway
很棒的答案,如果所有问题的答案都像这样好就好了。 - djack109
@juFo:请将您的问题作为一个新问题发布,并在此处链接到它。您是否查看了GitHub存储库?那里的代码对您是否有效? - Iain Galloway
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Iain Galloway
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接