我用的是RC2

使用URL路由:

routes.MapRoute(
    "Error",
     "{*url}",
     new { controller = "Errors", action = "NotFound" }  // 404s
);

上面似乎照顾到这样的请求(假设默认路由表由最初的MVC项目设置):"/blah/blah/blah/blah"

重写控制器本身的HandleUnknownAction():

// 404s - handle here (bad action requested
protected override void HandleUnknownAction(string actionName) {
    ViewData["actionName"] = actionName;
    View("NotFound").ExecuteResult(this.ControllerContext);
}  

但是,前面的策略不处理对坏/未知控制器的请求。例如,我没有“/IDoNotExist”,如果我请求这个,我从web服务器得到通用404页面,而不是我的404,如果我使用路由+覆盖。

最后,我的问题是:有没有办法在MVC框架中使用路由或其他东西来捕获这种类型的请求?

或者我应该默认使用Web。配置customErrors作为我的404处理程序,忘记这一切?我假设如果我使用customErrors,由于Web的原因,我将不得不在/Views之外存储通用404页面。配置直接访问限制。


当前回答

处理ASP中的错误。NET MVC就是个麻烦。我在这个页面和其他问题和网站上尝试了很多建议,都没有什么效果。一个建议是处理网络上的错误。系统内部配置。web服务器,但只返回空白页。

当我想出这个解决方案时,我的目标是;

不重定向 返回正确的STATUS CODES,而不是像默认的错误处理那样返回200/Ok

这是我的解决方案。

1.将以下内容添加到系统中。网络部分

   <system.web>
     <customErrors mode="On" redirectMode="ResponseRewrite">
      <error statusCode="404"  redirect="~/Error/404.aspx" />
      <error statusCode="500" redirect="~/Error/500.aspx" />
     </customErrors>
    <system.web>

上面的处理没有路由处理的任何url。配置和未处理的异常,特别是在视图上遇到的异常。注意我用的是aspx而不是html。这样我就可以在后面的代码上添加响应代码。

2. 在项目的根目录下创建一个名为Error的文件夹(或者其他你喜欢的文件夹),并添加这两个webform。下面是我的404页面;

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="404.aspx.cs" Inherits="Myapp.Error._404" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title >Page Not found</title>
    <link href="<%=ResolveUrl("~/Content/myapp.css")%>" rel="stylesheet" />
</head>
<body>
    <div class="top-nav">
      <a runat="server" class="company-logo" href="~/"></a>
    </div>
    <div>
        <h1>404 - Page Not found</h1>
        <p>The page you are looking for cannot be found.</p>
        <hr />
        <footer></footer>
    </div>
</body>
</html>

在后面的代码上,我设置了响应代码

protected void Page_Load(object sender, EventArgs e)
{
    Response.StatusCode = 404;
}

对500页做同样的处理吗

3.来处理控制器内的错误。有很多方法可以做到。这对我来说很管用。我所有的控制器都继承自一个基本控制器。在基本控制器中,我有以下方法

protected ActionResult ShowNotFound()
{
    return ShowNotFound("Page not found....");
}

protected ActionResult ShowNotFound(string message)
{
    return ShowCustomError(HttpStatusCode.NotFound, message);
}

protected ActionResult ShowServerError()
{
    return ShowServerError("Application error....");
}

protected ActionResult ShowServerError(string message)
{
    return ShowCustomError(HttpStatusCode.InternalServerError, message);
}

protected ActionResult ShowNotAuthorized()
{
    return ShowNotAuthorized("You are not allowed ....");

}

protected ActionResult ShowNotAuthorized(string message)
{
    return ShowCustomError(HttpStatusCode.Forbidden, message);
}

protected ActionResult ShowCustomError(HttpStatusCode statusCode, string message)
{
    Response.StatusCode = (int)statusCode;
    string title = "";
    switch (statusCode)
    {
        case HttpStatusCode.NotFound:
            title = "404 - Not found";
            break;
        case HttpStatusCode.Forbidden:
            title = "403 - Access Denied";
            break;
        default:
            title = "500 - Application Error";
            break;
    }
    ViewBag.Title = title;
    ViewBag.Message = message;
    return View("CustomError");
}

4.添加CustomError。cshtml到共享视图文件夹。下面是我的;

<h1>@ViewBag.Title</h1>
<br />
<p>@ViewBag.Message</p>

在你的应用控制器中,你可以这样做;

public class WidgetsController : ControllerBase
{
  [HttpGet]
  public ActionResult Edit(int id)
  {
    Try
    {
       var widget = db.getWidgetById(id);
       if(widget == null)
          return ShowNotFound();
          //or return ShowNotFound("Invalid widget!");
       return View(widget);
    }
    catch(Exception ex)
    {
       //log error
       logger.Error(ex)
       return ShowServerError();
    }
  }
}

现在是警告。 它不会处理静态文件错误。因此,如果您有一个路由,例如example.com/widgets,用户将其更改为example.com/widgets.html,他们将获得IIS默认错误页面,因此您必须以其他方式处理IIS级别的错误。

其他回答

我浏览了这个帖子上的大部分解决方案。虽然这个问题可能很老了,但即使是现在,它仍然非常适用于新项目,所以我花了很多时间阅读这里和其他地方给出的答案。

正如@Marco指出的404错误可能发生的不同情况,我根据这个列表检查了我一起编译的解决方案。除了他的要求之外,我还增加了一项。

解决方案应该能够以最合适的方式处理MVC以及AJAX/WebAPI调用。(例如,如果在MVC中发生404,它应该显示Not Found页面,如果在WebAPI中发生404,它不应该劫持XML/JSON响应,以便消费Javascript可以很容易地解析它)。


这个解是2倍的:

第一部分来自https://stackoverflow.com/a/27354140/2310818的@Guillaume。他们的解决方案处理了由于无效路由、无效控制器和无效动作而导致的任何404。

这个想法是创建一个WebForm,然后让它调用MVC错误控制器的NotFound动作。它做所有这些没有任何重定向,所以你不会看到一个302在小提琴手。原始URL也被保留,这使得这个解决方案非常棒!


第二部分来自@Germán在https://stackoverflow.com/a/5536676/2310818。他们的解决方案照顾任何404返回你的行为在HttpNotFoundResult()或抛出新的HttpException()的形式!

其思想是让一个过滤器查看由MVC控制器抛出的响应和异常,并在错误控制器中调用适当的操作。再次,这个解决方案的工作没有任何重定向和原始url被保留!


正如您所看到的,这两个解决方案一起提供了一个非常健壮的错误处理机制,它们实现了@Marco列出的所有需求以及我的需求。如果你想看这个解决方案的工作示例或演示,请在评论中留下,我很乐意把它放在一起。

我浏览了所有的文章,但没有一篇对我有用: 我的要求用户键入任何在您的url自定义404页面应该显示。我认为它非常直截了当。但是你应该正确理解404的处理:

 <system.web>
    <customErrors mode="On" redirectMode="ResponseRewrite">
      <error statusCode="404" redirect="~/PageNotFound.aspx"/>
    </customErrors>
  </system.web>
<system.webServer>
    <httpErrors errorMode="Custom">
      <remove statusCode="404"/>
      <error statusCode="404" path="/PageNotFound.html" responseMode="ExecuteURL"/>
    </httpErrors>
</system.webServer>

我发现这篇文章很有帮助。应该马上读。自定义错误页面- ben Foster

我的解决方案,以防有人觉得有用。

在web . config:

<system.web>
    <customErrors mode="On" defaultRedirect="Error" >
      <error statusCode="404" redirect="~/Error/PageNotFound"/>
    </customErrors>
    ...
</system.web>

在控制器/ ErrorController.cs:

public class ErrorController : Controller
{
    public ActionResult PageNotFound()
    {
        if(Request.IsAjaxRequest()) {
            Response.StatusCode = (int)HttpStatusCode.NotFound;
            return Content("Not Found", "text/plain");
        }

        return View();
    }
}

添加一个PageNotFound。cshtml放在共享文件夹中,就是这样。

加上我的解决方案,这几乎是相同的Herman Kan的,有一个小皱纹,让它工作在我的项目。

创建一个自定义错误控制器:

public class Error404Controller : BaseController
{
    [HttpGet]
    public ActionResult PageNotFound()
    {
        Response.StatusCode = 404;
        return View("404");
    }
}

然后创建一个自定义控制器工厂:

public class CustomControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        return controllerType == null ? new Error404Controller() : base.GetControllerInstance(requestContext, controllerType);
    }
}

最后,向自定义错误控制器添加一个覆盖:

protected override void HandleUnknownAction(string actionName)
{
    var errorRoute = new RouteData();
    errorRoute.Values.Add("controller", "Error404");
    errorRoute.Values.Add("action", "PageNotFound");
    new Error404Controller().Execute(new RequestContext(HttpContext, errorRoute));
}

就是这样。不需要网络。配置更改。

因为我的评论太长了,所以发表了一个答案…

这既是对独角兽帖子/答案的评论,也是对它的问题:

https://stackoverflow.com/a/7499406/687549

比起其他答案,我更喜欢这个答案,因为它很简单,而且事实是,显然微软的一些人被咨询了。然而,我有三个问题,如果他们可以回答,那么我将把这个答案称为互联网上所有404/500个错误答案的圣杯。NET MVC (x)应用程序。

@Pure。Krome

Can you update your answer with the SEO stuff from the comments pointed out by GWB (there was never any mentioning of this in your answer) - <customErrors mode="On" redirectMode="ResponseRewrite"> and <httpErrors errorMode="Custom" existingResponse="Replace">? Can you ask your ASP.NET team friends if it is okay to do it like that - would be nice to have some confirmation - maybe it's a big no-no to change redirectMode and existingResponse in this way to be able to play nicely with SEO?! Can you add some clarification surrounding all that stuff (customErrors redirectMode="ResponseRewrite", customErrors redirectMode="ResponseRedirect", httpErrors errorMode="Custom" existingResponse="Replace", REMOVE customErrors COMPLETELY as someone suggested) after talking to your friends at Microsoft?

就像我说的;如果我们能让你的回答更完整就太好了,因为这似乎是一个相当受欢迎的问题,有54000 +的浏览量。

更新:Unicorn的答案是302 Found和200 OK,不能使用路由更改为只返回404。它必须是一个物理文件,不是很MVC:ish。我们来看另一个解。太糟糕了,因为这似乎是到目前为止的终极MVC:ish答案。