c# - 确保特定异常始终导致给定的 HTTP 响应状态代码
问题描述
要求
我有一个 ASP.Net MVC 应用程序,它可以与许多不同的库一起使用。与大多数库一样,各种函数调用可能会引发许多不同的异常之一。
目前,无论何时抛出任何异常,MVC 应用程序都会“处理”它们并将“内部服务器错误”(代码 500)返回给客户端(例如 Web 浏览器)。
这在大多数情况下都很好,但是,有一种特定的异常类型(在这种情况下UnauthorizedAccessException
)我希望在响应中发送“未经授权”(代码 401)状态,而不是通常的 500 错误。
当前尝试
我做了一些研究,看起来“捕获”所有异常并处理它们的方法是使用该Application_Error
方法。Application_Error
所以我在课堂上尝试了以下实现MvcApplication
:
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,但客户端/浏览器仍然收到 500 错误。
我希望发生这种情况有一个很好的理由,但是我已经用尽了我的大脑来思考搜索词,这将为我提供我需要的答案。
问题
简而言之,我需要做什么才能获得我正在寻找的行为?
有关其他信息,最终我想要的是UnauthorizedAccessException
具有与 MVC 如何处理未经身份验证的请求(重定向到登录页面)相同的行为。但是,我还需要它来处理 AJAX 请求,因为我的 javascript 可以检查401
错误并执行一些特定的逻辑(在这种情况下,重定向到登录页面的响应不可行)
解决方案
一个聪明的方法是创建一个基本控制器,你的控制器继承默认控制器。在那里,您继承了默认的 Controller 类并覆盖了 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,服务器将返回 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();
在开始修改错误处理程序中的响应对象之前调用是个好主意。
推荐阅读
- python - 如何在python列表中打印特定索引的元素?
- python-3.x - 我想要'td'的文本,但它给出了错误另外,我没有标签(我想完全删除它,只想要其中包含的文本)
- android - 获取 Google Beacon 的距离和 UUID
- ggplot2 - 安排地块的困难
- html - 导航栏面板与文本重叠
- reactjs - 搜索功能在 React 中无法始终如一地工作
- python - 分配前引用的 /cart/slug/ 局部变量“产品”处的 UnboundLocalError
- html - 字体真棒图标加载“移位”一个角度
- javascript - 如何使用 javaScript 设置服务器端面板的数据源
- javascript - 在打字稿中完成异步函数后的事件