确保特定异常始终导致给定的 HTTP 响应状态代码
Ensure that a specific exception always results in a given HTTP response status code
要求
我有一个 ASP.Net MVC 应用程序,可以与许多不同的库一起使用。与大多数库一样,各种函数调用可能会导致抛出许多不同的异常之一。
目前,无论何时抛出任何异常,然后 MVC 应用程序 'handles' 它们和 returns 一个 "internal server error" (代码 500)返回客户端(例如网络浏览器)。
这在大多数情况下都很好,但是,有一种特定的异常类型(在本例中为 UnauthorizedAccessException
)我希望导致发送 "Unauthorized"(代码 401)状态在响应中,而不是通常的 500 错误。
当前尝试
我做了一些研究,看起来 'catch' 所有异常并处理它们的最佳方式是使用 Application_Error
方法。所以我在 MvcApplication
class 中尝试了 Application_Error
的以下实现:
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if(ex is UnauthorizedAccessException)
{
Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
}
}
问题
这里的问题是,虽然我可以调试并看到 Response.StatusCode
被设置为 401,但 client/browser 仍然收到 500 错误。
我认为发生这种情况有一个很好的理由,但我已经用尽了我的大脑来思考可以为我提供所需答案的搜索词。
问题
简而言之,我需要做什么才能获得我正在寻找的行为?
有关其他信息,最终我想要的是 UnauthorizedAccessException
具有与 MVC 处理未经身份验证的请求(重定向到登录页面)的方式相同的行为。但是,我还需要它来处理 AJAX 请求,因为我的 javascript 可以检查 401
错误并执行一些特定的逻辑(在这种情况下,响应重定向到登录页面是不可行的)
一个聪明的方法是创建一个基础控制器,您的控制器继承默认控制器。在那里你继承了默认的 Controller class 并覆盖了 OnException 方法。
public abstract class BaseController : Controller
{
protected override void OnException(System.Web.Mvc.ExceptionContext filterContext)
{
var responseCode = Response.StatusCode;
var exception = filterContext.Exception;
switch (exception.GetType().ToString())
{
case "UnauthorizedAccessException":
responseCode = 401;
filterContext.ExceptionHandled = true;
break;
}
Response.StatusCode = responseCode;
base.OnException(filterContext);
}
}
使它起作用的技巧是 filterContext.ExceptionHandled = true;
如果您不将其设置为 true,服务器将 return 500。
您的控制器将继承 BaseController
;
public class UserController : BaseController
{
public ActionResult Index(){
return View();
}
}
您需要添加到此代码的是重定向到登录页面,到您的 OnException
方法(如果需要)。我会为你做,但我没有足够的时间为你编写和测试它。目前正在等待自动化测试完成。:-)
编辑:
我没有意识到你的视图也会抛出错误,控制器显然不会处理这些错误。
在这种情况下,我们可以在 Global.asax 上恢复到原始的 Application_Error 方法。
我们需要的是两行代码..
Response.StatusCode = 401;
Response.End();
第一行设置状态码为401,
第二行此时结束执行并触发EndRequest事件,所以StatusCode不会修改为500。
如果您想在回复中附加一条消息:
Response.Write("Oops, you're not authorized...");
在开始修改错误处理程序中的响应对象之前调用 Response.Clear();
是个好主意。
要求
我有一个 ASP.Net MVC 应用程序,可以与许多不同的库一起使用。与大多数库一样,各种函数调用可能会导致抛出许多不同的异常之一。
目前,无论何时抛出任何异常,然后 MVC 应用程序 'handles' 它们和 returns 一个 "internal server error" (代码 500)返回客户端(例如网络浏览器)。
这在大多数情况下都很好,但是,有一种特定的异常类型(在本例中为 UnauthorizedAccessException
)我希望导致发送 "Unauthorized"(代码 401)状态在响应中,而不是通常的 500 错误。
当前尝试
我做了一些研究,看起来 'catch' 所有异常并处理它们的最佳方式是使用 Application_Error
方法。所以我在 MvcApplication
class 中尝试了 Application_Error
的以下实现:
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if(ex is UnauthorizedAccessException)
{
Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
}
}
问题
这里的问题是,虽然我可以调试并看到 Response.StatusCode
被设置为 401,但 client/browser 仍然收到 500 错误。
我认为发生这种情况有一个很好的理由,但我已经用尽了我的大脑来思考可以为我提供所需答案的搜索词。
问题
简而言之,我需要做什么才能获得我正在寻找的行为?
有关其他信息,最终我想要的是 UnauthorizedAccessException
具有与 MVC 处理未经身份验证的请求(重定向到登录页面)的方式相同的行为。但是,我还需要它来处理 AJAX 请求,因为我的 javascript 可以检查 401
错误并执行一些特定的逻辑(在这种情况下,响应重定向到登录页面是不可行的)
一个聪明的方法是创建一个基础控制器,您的控制器继承默认控制器。在那里你继承了默认的 Controller class 并覆盖了 OnException 方法。
public abstract class BaseController : Controller
{
protected override void OnException(System.Web.Mvc.ExceptionContext filterContext)
{
var responseCode = Response.StatusCode;
var exception = filterContext.Exception;
switch (exception.GetType().ToString())
{
case "UnauthorizedAccessException":
responseCode = 401;
filterContext.ExceptionHandled = true;
break;
}
Response.StatusCode = responseCode;
base.OnException(filterContext);
}
}
使它起作用的技巧是 filterContext.ExceptionHandled = true;
如果您不将其设置为 true,服务器将 return 500。
您的控制器将继承 BaseController
;
public class UserController : BaseController
{
public ActionResult Index(){
return View();
}
}
您需要添加到此代码的是重定向到登录页面,到您的 OnException
方法(如果需要)。我会为你做,但我没有足够的时间为你编写和测试它。目前正在等待自动化测试完成。:-)
编辑:
我没有意识到你的视图也会抛出错误,控制器显然不会处理这些错误。
在这种情况下,我们可以在 Global.asax 上恢复到原始的 Application_Error 方法。
我们需要的是两行代码..
Response.StatusCode = 401;
Response.End();
第一行设置状态码为401, 第二行此时结束执行并触发EndRequest事件,所以StatusCode不会修改为500。
如果您想在回复中附加一条消息:
Response.Write("Oops, you're not authorized...");
在开始修改错误处理程序中的响应对象之前调用 Response.Clear();
是个好主意。