MVC AJAX 请求返回的状态代码不正确

Incorrect Status Code returned on MVC AJAX Request

我正在提交标准 $.ajax() 请求,如下所示:

$.ajax({
    type: "GET",
    url: myUrl
    success: function(data) {
        $("#replace").html(data)
    },
    error: function (data) {
        console.warn(data);
    }
});

或者通过将处理程序附加到 ajax promise 回调来实现同样的效果,如下所示:

$.ajax({
    type: "GET",
    url: myUrl
})
.done(function(data, status) {
    console.log(data);
})
.fail(function(data, status) {
    console.warn(status);
});

在这两种情况下,或者当使用 $.ajaxError() handler 时,error/fail 函数在 returned HTTP 状态错误时被调用。


在我的 ASP.NET MVC 项目中,我正在尝试 return 正确的 HTTP 状态代码 ,这既是出于语义原因,也是为了被正确的客户端处理程序。

尝试 #1 - 正如 this answer I've tried to return a HttpStatusCodeResult 建议的那样:

protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
    if (filterContext.HttpContext.Request.IsAjaxRequest())
    {
        filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.Unauthorized, accessResult.AccessDeniedMessage);
        filterContext.HttpContext.Response.End();
    }
    else
    {
       base.HandleUnauthorizedRequest(filterContext);
    }
}

尝试 #2 - 或者,按照 this answer, I've tried returning a JsonResult and also setting the Response.StatusCode

的建议
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
filterContext.Result = new JsonResult()
{
    Data = new { Error = "Unauthorized User" },
    JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
filterContext.HttpContext.Response.End();

在这两种情况下,响应仍然返回 200 OK

问题:


上的这个问题似乎是 运行 相同的错误,但没有提出服务器端解决方案,而是仅允许 OK 错误状态代码并抓取响应以确定如果发生错误。

违规问题确实与 中的相同。成功返回响应,但陷入重定向到表单登录

<b>X-Responded-JSON</b>: {"status": 401, "headers": {"location":"http:\/\/localhost:50004\/Login?ReturnUrl=%2FClient"}}

虽然这个问题似乎没有建议服务器端解决方案,而是简单地依赖于在客户端解析错误状态。 Brock AllenUsing cookie authentication middleware with Web API and 401 response codes 上的 post 中建议服务器端修复:

Normally when using cookie authentication middleware, when the server (MVC or WebForms) issues a 401, then the response is converted to a 302 redirect to the login page (as configured by the LoginPath on the CookieAuthenticationOptions). But when an Ajax call is made and the response is a 401, it would not make sense to return a 302 redirect to the login page. Instead you’d just expect the 401 response to be returned. Unfortunately this is not the behavior we get with the cookie middleware — the response is changed to a 200 status code with a JSON response body with a message:

{"Message":"Authorization has been denied for this request."}

I’m not sure what the requirement was for this feature. To alter it, you must take over control of the behavior when there is a 401 unauthorized response by configuring a CookieAuthenticationProvider on the cookie authentication middleware:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
   AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
   LoginPath = new PathString("/Account/Login"),
   Provider = new CookieAuthenticationProvider
   {
      OnApplyRedirect = ctx =>
      {
         if (!IsAjaxRequest(ctx.Request))
         {
            ctx.Response.Redirect(ctx.RedirectUri);
         }
     }
   }
});

Notice it handles the OnApplyRedirect event. When the call is not an Ajax call, we redirect. Otherwise, we do nothing which allows the 401 to be returned to the caller.

The check for IsAjaxRequest is simply copied from a helper in the katana project:

private static bool IsAjaxRequest(IOwinRequest request)
{
   IReadableStringCollection query = request.Query;
   if ((query != null) && (query["X-Requested-With"] == "XMLHttpRequest"))
   {
      return true;
   }
   IHeaderDictionary headers = request.Headers;
   return ((headers != null) && (headers["X-Requested-With"] == "XMLHttpRequest"));
}