更改ajax请求的response.statuscode会引发错误"服务器无法在发送HTTP标头后设置状态"

Sha*_*run 5 c# asp.net asp.net-mvc asp.net-ajax asp.net-mvc-5

我正在一个MVC项目中工作,其中每个操作方法的用户角色和权限都存储在数据库中.我想要实现的是通过重写AuthorizeAttribute在mvc中使用授权过滤器功能.这样我就可以全局注册我的自定义授权过滤器.

这是我想要做的,遵循这个方法.我正在关注这篇文章来处理ajax请求.

protected override bool AuthorizeCore(HttpContextBase httpContext)
{
     //Custom permission checking logic 
     return false;//no permission for all methods-Just for testing
}

public override void OnAuthorization(AuthorizationContext filterContext)
{
    base.OnAuthorization(filterContext);
    CheckIfUserIsAuthenticated(filterContext);}
}

private void CheckIfUserIsAuthenticated(AuthorizationContext filterContext)
{
    // If Result is null, we’re OK: the user is authenticated and authorized. 
    if (filterContext.Result == null)
        return;

    var httpContext = filterContext.HttpContext;
    var request = httpContext.Request;
    var response = httpContext.Response;

    var user = httpContext.User;
    // If here, you’re getting an HTTP 401 status code. In particular,
    // filterContext.Result is of HttpUnauthorizedResult type. Check Ajax here. 

    if (request.IsAjaxRequest())
    {
        if (user.Identity.IsAuthenticated == false)
            response.StatusCode = (int)HttpStatusCode.Unauthorized;//401
        else
            response.StatusCode = (int)HttpStatusCode.Forbidden;//403

        response.SuppressFormsAuthenticationRedirect = true;

        response.End();// This line is causing the problems

        return;
    }

    if (user.Identity.IsAuthenticated)
    {
        //Redirect to customerror page
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是当我使用ajax post调用方法时,我的自定义异常过滤器正在捕获错误说"Server cannot set status after HTTP headers have been sent " 如果我删除response.End(),我在ajax错误处理程序方法而不是403中得到401响应.我试过

 HttpContext.Current.ApplicationInstance.CompleteRequest()
Run Code Online (Sandbox Code Playgroud)

而不是response.end,但后来我也得到401错误

反正有没有避免这种例外?

更新 我在javascript中使用这个通用错误处理程序方法来捕获所有ajax请求错误(我需要正确的响应状态代码):

 function ajaxFailed(xhr, textstatus, errorthrown) {
    debugger;
    if (textstatus == "error") {
        if (xhr.status == 401) {
            window.location = "/Account/Login";
        }
        if (xhr.status == 403) {
            $("#divoutput").html("you don't have permission.");
        }
    }
    if (xhr.status == 500) {
        $("#divoutput").append("<br/> internal servererror." + xhr.responseText);
    }
}
Run Code Online (Sandbox Code Playgroud)

更新2: 我当前的解决方案: 检查我的自定义异常处理程序过滤器中引发的异常的Exception.Message属性,如果消息是:"服务器无法在发送HTTP标头后设置状态",则忽略它.

我知道这是一种效率低下的方法,但我还没有其他解决方案.等待一个好的解决方案:)

VMA*_*Atm 0

尝试更改处理请求的顺序:

public override void OnAuthorization(AuthorizationContext filterContext)
{
    CheckIfUserIsAuthenticated(filterContext);}
    base.OnAuthorization(filterContext);
}
Run Code Online (Sandbox Code Playgroud)

更新

您链接的文章说您必须处理其他事件处理程序方法 HandleUnauthorizedRequest

protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
Run Code Online (Sandbox Code Playgroud)

不是OnAuthorization像你那样。

更新#2
尝试使用缓冲输出

Response.BufferOutput = true;
Run Code Online (Sandbox Code Playgroud)

因此您的服务器无法将标头发送回客户端。