14

我有一个 ASP.net MVC 5 项目,其中包含特定“API”区域中的 WebAPI。我在 web.config 中启用了 IIS7 错误处理,如下所示:

<system.webServer>
    <httpErrors errorMode="Custom" existingResponse="Replace">
        <remove statusCode="400" subStatusCode="-1" />
        <remove statusCode="404" subStatusCode="-1" />
        <remove statusCode="500" subStatusCode="-1" />
        <error statusCode="400" path="400.html" responseMode="File" />
        <error statusCode="404" path="404.html" responseMode="File" />
        <error statusCode="500" path="500.html" responseMode="File" />
    </httpErrors>
</system.webServer>

当 404/500 等发生时,这会向 MVC 网站的用户显示友好的消息。当从 WebAPI 返回特定的(合法的)状态代码(例如,调用 `/api/token' 时返回 400)时,我的问题就出现了。在这些情况下,响应的 JSON 内容被 IIS 拦截,并且我的友好消息 HTML 作为响应返回,而不是来自 WebAPI 的原始 JSON。是否可以从 IIS 错误处理中排除“API”区域?如果无法做到这一点,允许 ASP.net MVC 网站友好消息和 WebAPI JSON 响应共存的正确解决方案是什么?

4

1 回答 1

14

经过大量阅读和实验,我发现这种设置组合可以有效地工作:

友好的错误页面

每个响应状态代码一个 aspx 和一个 html 页面(这是我的):

  • 404.aspx
  • 404.html
  • 500.aspx
  • 500.html

两个页面之间的唯一区别是 aspx 页面包含以下行:

<% Response.StatusCode = 500 %>
<% Response.TrySkipIisCustomErrors = true %>

第一行将正确的 HTTP 状态代码发送回客户端,第二行试图说服 IIS 它不需要自己处理响应。

Web.config 设置

自定义错误应该是on, 或remoteonly, 并指向 aspx 文件:

<customErrors mode="On" defaultRedirect="500.aspx" redirectMode="ResponseRewrite">
  <error statusCode="404" redirect="404.aspx" />
</customErrors>

IIS 自定义错误也应该打开,并指向该system.webServer部分中的 html 文件:

<httpErrors errorMode="Custom" existingResponse="Auto">
  <remove statusCode="404" subStatusCode="-1" />
  <remove statusCode="500" subStatusCode="-1" />
  <error statusCode="404" path="404.html" responseMode="File" />
  <error statusCode="500" path="500.html" responseMode="File" />
</httpErrors>

如果设置了标志,则告诉existingResponse="Auto"IIS 仅返回友好错误页面。SetStatus实际上,这允许 ASP.net 从该customErrors部分发回自定义响应、它自己的自定义错误页面,或者允许 IIS 返回配置的友好错误页面。

FilterConfig.cs 设置

默认的 ASP.net MVC/WebAPI 项目配置有一个HandleErrorAttribute过滤器,该过滤器处理从操作引发的异常并返回正确配置的自定义错误页面。我已经扩展了这个类,通过从这个类派生来处理来自 WebAPI 操作的异常:

filters.Add(new HandleExceptionAttribute());

处理异常属性

public class HandleExceptionAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAjaxRequest() && filterContext.Exception != null)
        {
            filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            filterContext.HttpContext.Response.StatusDescription = filterContext.Exception.Message;
            filterContext.ExceptionHandled = true;
            filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
        }
        else
        {
            base.OnException(filterContext);
        }
    }
}

此类处理来自 WebAPI 操作的异常,并将异常消息作为 JSON 响应(具有正确的 HTTP 状态)返回给调用者。如果您的异常消息对用户不友好,或者如果客户端不知道如何解释这些消息,您可能不想这样做。

于 2014-06-02T09:30:19.573 回答