如何在.NET MVC 2中实现正确的HTTPerror handling?
我一直在努力整天在我的ASP.NET MVC 2应用程序中实现error handling。 我已经看过各种技术,但都没有正常工作。 我正在使用MVC2和.NET 4.0(在MVC3发布之前启动了项目;我们将在我们发布初始版本后进行升级)。
在这一点上,我会很乐意妥善处理404和500错误 – 403(需要授权)也会很好,其次是各种其他具体的回应。 现在,我可以在404之前全部拿到404,全部500,全部302,在500之前全部拿到302。
这是我的要求(它应该非常接近HTTP的基本要求):
-
如果找不到资源,则抛出一个404,并显示一个404请求的URL的特定页面。 不要像302那样返回一个中间响应代码。理想情况下,保持请求的URL,而不是像
/Error/NotFound
那样显示一个新的URL,但是如果后者显示,确保我们没有返回redirect响应来获取它。 -
如果发生内部服务器错误,请抛出500,并显示一个500特定的错误,并指出错误的位置。 同样,不要返回中间响应代码,理想情况下不要更改URL。
以下是我想要的404:
- 找不到静态文件:
/Content/non-existent-dir/non-existent-file.txt
- 未find控制器:
/non-existent-controller/Foo/666
- find控制器,但未find操作:
/Home/non-existent-action/666
- find控制器和操作,但操作无法find请求的对象:
/Home/Login/non-existent-id
以下是我认为的500:
- 发布一个错误的值:
POST /User/New/new-user-name-too-long-for-db-column-constraint
- 与数据无关的问题,如Web Service端点未响应
其中一些问题需要通过特定的控制器或模型来识别,然后控制器应该抛出相应的HttpException。 其余的应该更通用地处理。
对于404情况#2,我试图使用自定义的ControllerFactory来抛出404如果控制器无法find。 对于404情况#3,我试图使用一个自定义的基本控制器来覆盖HandleUnknownAction
并抛出404。
在这两种情况下,我在404之前得到了一个302.而且,我从来没有得到500个错误; 如果我修改Web.config来在我的Web服务端点input一个拼写错误,我仍然得到一个302,然后一个404说不能find使用 Web服务的URL(控制器/操作)。 我也得到请求的URL作为(不需要的)查询string参数: /Error/NotFound?aspxerrorpath=/Home/non-existent-action
这两种技术来自http://www.niksmit.com/wp/?p=17 (如何使用ASP.Net MVC获得正常的404(页面未find)错误页面),从http:// richarddingwall指出。名称/ 2008/08/17 /为基础的战略,为资源-404-错误-在-ASPNET-MVC /
如果在Web.config中有<customErrors mode="On" defaultRedirect="~/Error/Unknown" redirectMode="ResponseRedirect" />
,我会得到相应的响应代码,但是我的Error控制器永远不会被调用。 取出redirectMode
属性让我的MVC错误的意见,但与一个介入302和一个更改的URL – 总是相同的控制器( Unknown
= 500;如果我改变它NotFound
一切看起来像一个404)。
以下是我已阅读并尝试实施的其他一些内容:
- http://www.davidjuth.com/asp-net-mvc-error-handler.aspx
- http://sanjayuttam.com/wordpress/index.php/c-sharp/c-sharp-code-examples/error-handling-in-asp-net-mvc-1-part-2-of-2/
- http://blog.hebbink.com/post/2010/12/14/NET-custom-404-error-page-returns-302-for-http-status.aspx
- http://blog.dantup.com/2009/04/aspnet-mvc-handleerror-attribute-custom.html
- http://weblogs.asp.net/scottgu/archive/2008/07/14/asp-net-mvc-preview-4-release-part-1.aspx
..以及一堆StackOverflowpost。
在我看来,这种error handling对于Web应用程序来说是非常基本的,而MVC框架应该有默认的function,并且让其他人可以扩展它。 也许他们会在未来的版本中做到这一点。 与此同时,有人可以给我全面的细节,如何实施适当的HTTP响应?
这是你可以使用的一种技术。 定义一个将提供错误页面的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"); } }
然后在Global.asax
您可以订阅Application_Error
事件,您可以在其中loggingexception并执行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)); }
现在剩下的就是开始抛出适当的例外:
public class HomeController : Controller { public ActionResult Index() { throw new HttpException(404, "NotFound"); } }
对于HTTP 404错误(无redirect),看看我的博客文章的主题。 这可能会给你一些好主意:
http://hectorcorrea.com/blog/returning-http-404-in-asp-net-mvc/16
这不能回答你的问题,但重要的是要注意,HTTP状态500表明服务器出了问题,所以你的例子:
POST /User/New/new-user-name-too-long-for-db-column-constraint
是不是有效的理由扔500,其数据validation问题,应该由MVC数据注释或jQueryvalidation框架或等处理。只是在文本框旁边显示一个错误消息说“用户名太长”是好多了。