如何在.NET MVC 2中实现正确的HTTP错误处理?

Val*_*Val 39 error-handling asp.net-mvc http httpresponse asp.net-mvc-2

我一整天都在努力在我的ASP.NET MVC 2应用程序中实现错误处理.我看过各种各样的技术,但都没有正常工作.我正在使用MVC2和.NET 4.0(在MVC3发布之前启动项目;我们将在发布初始版本后进行升级).

在这一点上,我将很乐意正确处理404和500错误 - 403(需要授权)也会很好,其次是各种其他特定的响应.现在,我得到所有404,全部500,全部302在404之前,或者全部302在500之前.

这是我的要求(应该非常接近HTTP的基本要求):

  • 如果找不到资源,则抛出404,并显示包含所请求URL的特定于404的页面.不要返回像302这样的中间响应代码.理想情况下,保留请求的URL,而不是显示新的URL /Error/NotFound,但如果显示后者,请确保我们没有返回重定向响应来获取它.

  • 如果发生内部服务器错误,则抛出500,并显示500特定错误,并指出出现了什么问题.同样,不要返回中间响应代码,理想情况下不要更改URL.

这是我认为的404:

  1. 找不到静态文件: /Content/non-existent-dir/non-existent-file.txt
  2. 未找到控制器: /non-existent-controller/Foo/666
  3. 找到控制器,但未找到操作: /Home/non-existent-action/666
  4. 找到控制器和操作,但操作找不到请求的对象: /Home/Login/non-existent-id

这是我认为的500:

  1. 发布一个不好的价值: POST /User/New/new-user-name-too-long-for-db-column-constraint
  2. 非数据相关问题,如Web服务端点无响应

其中一些问题需要由特定的控制器或模型识别,然后控制器应抛出适当的HttpException.其余的应该更一般地处理.

对于404情况#2,如果找不到控制器,我尝试使用自定义ControllerFactory来抛出404.对于404#3案例,我试图使用自定义基本控制器来覆盖HandleUnknownAction并抛出404.

在这两种情况下,我在404之前得到302.而且,我从来没有得到500个错误; 如果我修改Web.config以在我的Web服务端点中输入拼写错误,我仍然得到302,然后404表示无法找到使用 Web服务的URL(控制器/操作).我还将请求的URL作为(不需要的)查询字符串参数获取:/Error/NotFound?aspxerrorpath=/Home/non-existent-action

这两种技术都来自http://www.niksmit.com/wp/?p=17(如何使用ASP.Net MVC获取正常的404(找不到页面)错误页面),来自http:// richarddingwall .名称/ 2008/08/17 /为基础的战略,为资源-404-错误-在-ASPNET-MVC /

如果在我的Web.config中<customErrors mode="On" defaultRedirect="~/Error/Unknown" redirectMode="ResponseRedirect" />,我得到了相应的响应代码,但我的错误控制器永远不会被调用.取出redirectMode属性可以获得MVC错误视图,但是介入302和更改的URL - 并且始终是相同的控制器(Unknown= 500;如果我将其更改为NotFound一切看起来像404).

以下是我已阅读并尝试实施的其他一些内容:

..以及一堆StackOverflow帖子.

在我看来,这种错误处理对于Web应用程序来说是非常基本的,并且MVC框架应该具有开箱即用的默认设置,并且让人们将其扩展为其他工作.也许他们会在将来的版本中做到这一点.在此期间,有人可以向我提供有关如何实施正确HTTP响应的全面详细信息吗?

Dar*_*rov 49

这是您可以使用的一种技术.定义ErrorsController将为错误页面提供服务的内容:

public class ErrorsController : Controller
{
    public ActionResult Http404()
    {
        Response.StatusCode = 404;
        return Content("404", "text/plain");
    }

    public ActionResult Http500()
    {
        Response.StatusCode = 500;
        return Content("500", "text/plain");
    }

    public ActionResult Http403()
    {
        Response.StatusCode = 403;
        return Content("403", "text/plain");
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在Global.asax您可以订阅Application_Error您可以记录异常并执行以下相应操作的事件ErrorsController:

protected void Application_Error(object sender, EventArgs e)
{
    var app = (MvcApplication)sender;
    var context = app.Context;
    var ex = app.Server.GetLastError();
    context.Response.Clear();
    context.ClearError();
    var httpException = ex as HttpException;

    var routeData = new RouteData();
    routeData.Values["controller"] = "errors";
    routeData.Values["exception"] = ex;
    routeData.Values["action"] = "http500";
    if (httpException != null)
    {
        switch (httpException.GetHttpCode())
        {
            case 404:
                routeData.Values["action"] = "http404";
                break;
            case 403:
                routeData.Values["action"] = "http403";
                break;
            case 500:
                routeData.Values["action"] = "http500";
                break;
        }
    }
    IController controller = new ErrorsController();
    controller.Execute(new RequestContext(new HttpContextWrapper(context), routeData));
}
Run Code Online (Sandbox Code Playgroud)

而现在剩下的就是开始抛出适当的例外:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        throw new HttpException(404, "NotFound");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Val,当找不到控制器时,ASP.NET MVC会自动抛出代码为404的HttpException,因此它将进入第一种情况. (2认同)