asp.net-mvc ASP.NET MVC 404 错误处理
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/717628/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ASP.NET MVC 404 Error Handling
提问by Clearly
Possible Duplicate:
How can I properly handle 404 in ASP.NET MVC?
I've made the changes outlined at 404 Http error handler in Asp.Net MVC (RC 5)and I'm still getting the standard 404 error page. Do I need to change something in IIS?
我已经在 Asp.Net MVC (RC 5)中的404 Http 错误处理程序中进行了更改,但我仍然得到标准的 404 错误页面。我需要更改 IIS 中的某些内容吗?
回答by Marco
I've investigated A LOTon how to properly manage 404s in MVC (specifically MVC3), and this, IMHO is the best solution I've come up with:
我已经研究了很多关于如何在 MVC (特别是 MVC3) 中正确管理 404s 的问题,恕我直言,这是我想出的最佳解决方案:
In global.asax:
在 global.asax 中:
public class MvcApplication : HttpApplication
{
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 404)
{
Response.Clear();
var rd = new RouteData();
rd.DataTokens["area"] = "AreaName"; // In case controller is in another area
rd.Values["controller"] = "Errors";
rd.Values["action"] = "NotFound";
IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
}
}
}
ErrorsController:
错误控制器:
public sealed class ErrorsController : Controller
{
public ActionResult NotFound()
{
ActionResult result;
object model = Request.Url.PathAndQuery;
if (!Request.IsAjaxRequest())
result = View(model);
else
result = PartialView("_NotFound", model);
return result;
}
}
Edit:
编辑:
If you're using IoC (e.g. AutoFac), you should create your controller using:
如果您使用 IoC(例如 AutoFac),您应该使用以下命令创建您的控制器:
var rc = new RequestContext(new HttpContextWrapper(Context), rd);
var c = ControllerBuilder.Current.GetControllerFactory().CreateController(rc, "Errors");
c.Execute(rc);
Instead of
代替
IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
(Optional)
(可选的)
Explanation:
解释:
There are 6 scenarios that I can think of where an ASP.NET MVC3 apps can generate 404s.
我可以想到 ASP.NET MVC3 应用程序可以生成 404 的 6 个场景。
Generated by ASP.NET:
由 ASP.NET 生成:
- Scenario 1:URL does not match a route in the route table.
- 场景一:URL与路由表中的路由不匹配。
Generated by ASP.NET MVC:
由 ASP.NET MVC 生成:
Scenario 2:URL matches a route, but specifies a controller that doesn't exist.
Scenario 3:URL matches a route, but specifies an action that doesn't exist.
场景 2:URL 匹配路由,但指定了一个不存在的控制器。
场景 3:URL 匹配路由,但指定了不存在的操作。
Manually generated:
手动生成:
Scenario 4:An action returns an HttpNotFoundResult by using the method HttpNotFound().
Scenario 5:An action throws an HttpException with the status code 404.
Scenario 6:An actions manually modifies the Response.StatusCode property to 404.
场景 4:操作使用 HttpNotFound() 方法返回 HttpNotFoundResult。
场景 5:一个动作抛出一个状态码为 404 的 HttpException。
场景 6:某个操作手动将 Response.StatusCode 属性修改为 404。
Objectives
目标
(A)Show a custom 404 error page to the user.
(B)Maintain the 404 status code on the client response (specially important for SEO).
(C)Send the response directly, without involving a 302 redirection.
(A)向用户显示自定义 404 错误页面。
(B)在客户端响应中维护 404 状态代码(对 SEO 尤其重要)。
(C)直接发送响应,不涉及 302 重定向。
Solution Attempt: Custom Errors
解决方案尝试:自定义错误
<system.web>
<customErrors mode="On">
<error statusCode="404" redirect="~/Errors/NotFound"/>
</customErrors>
</system.web>
Problems with this solution:
此解决方案的问题:
- Does not comply with objective (A) in scenarios (1), (4), (6).
- Does not comply with objective (B) automatically. It must be programmed manually.
- Does not comply with objective (C).
- 不符合场景 (1)、(4)、(6) 中的目标 (A)。
- 不自动符合目标 (B)。它必须手动编程。
- 不符合目标 (C)。
Solution Attempt: HTTP Errors
解决方案尝试:HTTP 错误
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problems with this solution:
此解决方案的问题:
- Only works on IIS 7+.
- Does not comply with objective (A) in scenarios (2), (3), (5).
- Does not comply with objective (B) automatically. It must be programmed manually.
- 仅适用于 IIS 7+。
- 不符合场景 (2)、(3)、(5) 中的目标 (A)。
- 不自动符合目标 (B)。它必须手动编程。
Solution Attempt: HTTP Errors with Replace
解决方案尝试:带有替换的 HTTP 错误
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problems with this solution:
此解决方案的问题:
- Only works on IIS 7+.
- Does not comply with objective (B) automatically. It must be programmed manually.
- It obscures application level http exceptions. E.g. can't use customErrors section, System.Web.Mvc.HandleErrorAttribute, etc. It can't only show generic error pages.
- 仅适用于 IIS 7+。
- 不自动符合目标 (B)。它必须手动编程。
- 它掩盖了应用程序级别的 http 异常。例如,不能使用 customErrors 部分、System.Web.Mvc.HandleErrorAttribute 等。它不能只显示通用错误页面。
Solution Attempt customErrors and HTTP Errors
解决方案尝试 customErrors 和 HTTP 错误
<system.web>
<customErrors mode="On">
<error statusCode="404" redirect="~/Errors/NotFound"/>
</customError>
</system.web>
and
和
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problems with this solution:
此解决方案的问题:
- Only works on IIS 7+.
- Does not comply with objective (B) automatically. It must be programmed manually.
- Does not comply with objective (C) in scenarios (2), (3), (5).
- 仅适用于 IIS 7+。
- 不自动符合目标 (B)。它必须手动编程。
- 不符合场景 (2)、(3)、(5) 中的目标 (C)。
People that have troubled with this before even tried to create their own libraries (see http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html). But the previous solution seems to cover all the scenarios without the complexity of using an external library.
在尝试创建自己的库之前遇到过这个问题的人(参见http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html)。但是之前的解决方案似乎涵盖了所有场景,没有使用外部库的复杂性。
回答by Mike Chaliy
Yet another solution.
另一个解决方案。
Add ErrorControllers or static page to with 404 error information.
添加 ErrorControllers 或静态页面到带有 404 错误信息。
Modify your web.config (in case of controller).
修改您的 web.config(如果是控制器)。
<system.web>
<customErrors mode="On" >
<error statusCode="404" redirect="~/Errors/Error404" />
</customErrors>
</system.web>
Or in case of static page
或者在静态页面的情况下
<system.web>
<customErrors mode="On" >
<error statusCode="404" redirect="~/Static404.html" />
</customErrors>
</system.web>
This will handle both missed routes and missed actions.
这将处理错过的路线和错过的动作。
回答by Yousi
The response from Marco is the BEST solution. I needed to control my error handling, and I mean really CONTROL it. Of course, I have extended the solution a little and created a full error management system that manages everything. I have also read about this solution in other blogs and it seems very acceptable by most of the advanced developers.
Marco 的回应是最好的解决方案。我需要控制我的错误处理,我的意思是真正控制它。当然,我稍微扩展了解决方案并创建了一个完整的错误管理系统来管理所有内容。我也在其他博客中读到过这个解决方案,大多数高级开发人员似乎都可以接受。
Here is the final code that I am using:
这是我正在使用的最终代码:
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 404)
{
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.Clear();
Server.ClearError();
var routeData = new RouteData();
routeData.Values["controller"] = "ErrorManager";
routeData.Values["action"] = "Fire404Error";
routeData.Values["exception"] = exception;
Response.StatusCode = 500;
if (httpException != null)
{
Response.StatusCode = httpException.GetHttpCode();
switch (Response.StatusCode)
{
case 404:
routeData.Values["action"] = "Fire404Error";
break;
}
}
// Avoid IIS7 getting in the middle
Response.TrySkipIisCustomErrors = true;
IController errormanagerController = new ErrorManagerController();
HttpContextWrapper wrapper = new HttpContextWrapper(Context);
var rc = new RequestContext(wrapper, routeData);
errormanagerController.Execute(rc);
}
}
and inside my ErrorManagerController :
在我的 ErrorManagerController 里面:
public void Fire404Error(HttpException exception)
{
//you can place any other error handling code here
throw new PageNotFoundException("page or resource");
}
Now, in my Action, I am throwing a Custom Exception that I have created. And my Controller is inheriting from a custom Controller Based class that I have created. The Custom Base Controller was created to override error handling. Here is my custom Base Controller class:
现在,在我的 Action 中,我抛出了一个我创建的自定义异常。我的控制器继承自我创建的自定义基于控制器的类。创建自定义基本控制器是为了覆盖错误处理。这是我的自定义基本控制器类:
public class MyBasePageController : Controller
{
protected override void OnException(ExceptionContext filterContext)
{
filterContext.GetType();
filterContext.ExceptionHandled = true;
this.View("ErrorManager", filterContext).ExecuteResult(this.ControllerContext);
base.OnException(filterContext);
}
}
The "ErrorManager" in the above code is just a view that is using a Model based on ExceptionContext
上面代码中的“ErrorManager”只是一个使用基于ExceptionContext的Model的视图
My solution works perfectly and I am able to handle ANY error on my website and display different messages based on ANY exception type.
我的解决方案完美运行,我能够处理我网站上的任何错误,并根据任何异常类型显示不同的消息。
回答by Clearly
Looks like this is the best way to catch everything.
看起来这是捕捉一切的最佳方式。
回答by J.W.
In IIS, you can specify a redirect to "certain" page based on error code. In you example, you can configure 404 - > Your customized 404 error page.
在 IIS 中,您可以根据错误代码指定重定向到“特定”页面。在您的示例中,您可以配置 404 -> 您自定义的 404 错误页面。
回答by Mike Chaliy
What I can recomend is to look on FilterAttribute. For example MVC already has HandleErrorAttribute. You can customize it to handle only 404. Reply if you are interesed I will look example.
我可以推荐的是查看FilterAttribute。例如 MVC 已经有 HandleErrorAttribute。您可以自定义它以仅处理 404。如果您感兴趣,请回复我将查看示例。
BTW
顺便提一句
Solution(with last route) that you have accepted in previous question does not work in much of the situations. Second solution with HandleUnknownActionwill work but require to make this change in each controller or to have single base controller.
您在上一个问题中接受的解决方案(最后一条路线)在大多数情况下都不起作用。使用HandleUnknownAction 的第二种解决方案将起作用,但需要在每个控制器中进行此更改或具有单个基本控制器。
My choice is a solution with HandleUnknownAction.
我的选择是使用 HandleUnknownAction 的解决方案。

