【问题标题】:ASP.NET MVC 5 Custom Error PageASP.NET MVC 5 自定义错误页面
【发布时间】:2014-06-27 05:20:08
【问题描述】:

我在 ASP.NET MVC 5 应用程序中使用自定义授权属性,如下所示:

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext context)
    {
        if (context.HttpContext.Request.IsAuthenticated)
        {
            context.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);                
        }
        else
        {
            base.HandleUnauthorizedRequest(context);
        }
    }
}

在我的 web.config 的 system.web 部分中,我提到了错误路径,例如:

<system.web>
    <customErrors mode="On" defaultRedirect="/Error/Error">
      <error statusCode="403" redirect="/Error/NoPermissions"/>
    </customErrors>
</system.web>

但我从未被重定向到/Error/NoPermissions 的自定义错误页面。相反,浏览器会显示一般错误页面,上面写着“HTTP Error 403.0 - Forbidden”

【问题讨论】:

  • 你有名为 Error 的控制器,里面有 Action NoPermissions 吗?
  • 更改 的配置
  • 它没有用。好吧,在 MVC 4 应用程序中,我有类似 之类的配置,并且它有效很好。
  • 嗯,关于自定义错误,MVC 4 和 MVC5 之间没有太大区别。那里还有其他问题。也许你的控制器。确保它没有授权属性。
  • 我的错误控制器/操作没有任何属性。

标签: asp.net-mvc custom-error-pages custom-errors


【解决方案1】:

[1]:从 Web.config 中删除所有“customErrors”和“httpErrors”

[2]:检查 'App_Start/FilterConfig.cs' 看起来像这样:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }
}

[3]:在'Global.asax'中添加这个方法:

public void Application_Error(Object sender, EventArgs e)
{
    Exception exception = Server.GetLastError();
    Server.ClearError();

    var routeData = new RouteData();
    routeData.Values.Add("controller", "ErrorPage");
    routeData.Values.Add("action", "Error");
    routeData.Values.Add("exception", exception);

    if (exception.GetType() == typeof(HttpException))
    {
        routeData.Values.Add("statusCode", ((HttpException)exception).GetHttpCode());
    }
    else
    {
        routeData.Values.Add("statusCode", 500);
    }

    Response.TrySkipIisCustomErrors = true;
    IController controller = new ErrorPageController();
    controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
    Response.End();
}

[4]: 添加'Controllers/ErrorPageController.cs'

public class ErrorPageController : Controller
{
    public ActionResult Error(int statusCode, Exception exception)
    {
         Response.StatusCode = statusCode;
         ViewBag.StatusCode = statusCode + " Error";
         return View();
    }
}

[5]:在“视图/共享/Error.cshtml”中

@model System.Web.Mvc.HandleErrorInfo
@{
    ViewBag.Title = (!String.IsNullOrEmpty(ViewBag.StatusCode)) ? ViewBag.StatusCode : "500 Error";
}

<h1 class="error">@(!String.IsNullOrEmpty(ViewBag.StatusCode) ? ViewBag.StatusCode : "500 Error"):</h1>

//@Model.ActionName
//@Model.ControllerName
//@Model.Exception.Message
//@Model.Exception.StackTrace

:D

【讨论】:

  • 刚刚尝试实现这一点。访问不存在的页面不会返回任何内容。 (而不是 404)
  • 为了清楚起见,它返回一个404状态码,带有一个空白页面。
  • @Dementic:是的,它是一个空白页面,因此您可以自定义它。我现在在一些网站上运行良好。
  • 对不起,我的错。错过了什么。
  • 您的解决方案能否正常处理 AJAX 请求?此外,在您认识到它是 HttpException 错误之前清除服务器错误。
【解决方案2】:

谢谢大家,但问题不在于 403 代码。实际上问题出在我试图返回 403 的方式上。我只是将代码更改为抛出 HttpException 而不是返回 HttpStatusCodeResult,现在一切正常。我可以通过抛出 HttpException 异常来返回任何 HTTP 状态代码,而我的 customErrors 配置会捕获所有这些代码。可能是HttpStatusCodeResult 没有完成我预期的工作。

我刚换了

context.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);

throw new HttpException((int)System.Net.HttpStatusCode.Forbidden, "Forbidden");

就是这样。

编码愉快。

【讨论】:

  • 感谢分享最终解决方案,这实际上也帮助了我。从来没有想过只是抛出错误,尽管我想知道一直抛出异常的代价有多大。如果框架允许您轻松更改响应而不必重定向或抛出错误,那就太好了。
  • 您好,问题不在于 HttpStatusCodeResult,而在于 customErrors。如果您使用 httpErrors 那么它可以双向工作!为了更好地理解这个问题,你可以阅读这篇博文:dusted.codes/…
【解决方案3】:

我也有这个问题。除了web.config 文件中&lt;system.web&gt; 部分中的自定义错误代码外,OP 问题中的代码运行良好。要解决此问题,我需要将以下代码添加到 &lt;system.webServer&gt;。请注意‘webserver’ 而不是‘web’

<httpErrors errorMode="Custom" existingResponse="Replace">
  <remove statusCode="403" />
  <error statusCode="403" responseMode="ExecuteURL" path="/Error/UnAuthorized" />
</httpErrors>

如果有人使用以下环境,这里是完整的解决方案:

环境:

  • Visual Studio 2013 更新 4
  • 带有 ASP.NET MVC 5 的 Microsoft .NET Framework 4.5.1
  • 项目:带有 MVC 和身份验证的 ASP.NET Web 应用程序:个人用户帐户模板

自定义属性类:

将以下类添加到您网站的默认命名空间。在接受的答案Stack Overflow question:Why does AuthorizeAttribute redirect to the login page for authentication and authorization failures?中解释了这里的原因

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAuthenticated)
        {
            filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);

        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
} 

然后在web.config文件中添加如下代码

<system.webServer>
   <httpErrors errorMode="Custom" existingResponse="Replace">
      <remove statusCode="403" />
      <error statusCode="403" responseMode="ExecuteURL" path="/Error/UnAuthorized" />
   </httpErrors>
</system.webServer>

下面文章解释more about this: ASP.NET MVC: Improving the Authorize Attribute (403 Forbidden)

以及本文中的 httpErrors in web.config 部分:Demystifying ASP.NET MVC 5 Error Pages and Error Logging

然后将 ErrorController.cs 添加到 Controllers 文件夹

public class ErrorController : Controller
{
    // GET: UnAuthorized
    public ActionResult UnAuthorized()
    {
        return View();
    }

    public ActionResult Error()
    {
        return View();
    }

}

然后将 UnAuthorized.cshtml 添加到 View/Shared 文件夹

@{
    ViewBag.Title = "Your Request Unauthorized !"; //Customise as required
 }
 <h2>@ViewBag.Title.</h2> 

这将显示自定义错误页面,而不是浏览器生成的错误页面。

另请注意,对于上述环境,不需要按照其中一个答案的建议对模板添加的RegisterGlobalFilters方法内的代码进行注释。

请注意,我只是从我的工作项目中剪切和粘贴代码,因此我在上面的代码中使用 Unauthorized 而不是 OP 的 NoPermissions

【讨论】:

  • 这是我做的方式,但似乎无法使用此方法捕获到文件扩展名的404 URL。
  • 使用 ExecuteUrl 真的很糟糕。因为它搞砸了SEO。所以改用文件。
【解决方案4】:

这些似乎是复杂的解决方法。基本上,您需要做的就是让您的自定义错误页面 (CEP) 正常工作:

  1. 在您的控制器文件夹中添加一个错误控制器。
  2. 在您的错误控制器中,使用[HandleError] 注释
  3. 对于每个要显示 CEP 的错误,创建一个 ActionResult 方法。
  4. 在 ~/Views/Shared/Error 文件夹中为每个 CEP 创建一个视图,并根据需要自定义它。 (在创建控制器时应该已经创建了 Error 文件夹。如果没有,则需要先创建 Error 文件夹。)
  5. 在根级别打开 web.config 文件 *注意:有两 (2) 个 web.config 文件。一个在您的 Views 文件夹中,另一个在您的应用程序的根级别。
  6. &lt;system.web&gt; 内,添加&lt;customError mode="On" defaultRedirect="~/Error/Error"&gt;。您没有 CEP 的任何 statusCode 都将由 defaultRedirect 处理。
  7. 对于每个错误代码,您都有一个 CEP;添加&lt;error statusCode="[StatusCode]" redirect="~/Error/[CEP Name]"&gt;。您可以省略文件扩展名。

控制器示例:

namespace NAMESPACE_Name.Controllers
{
    [HandleError]
    public class ErrorController : Controller
    {
        // GET: Error
        public ActionResult BadRequest()
        {
            return View();
        }

        public ActionResult Error()
        {
            return View();
        }

        public ActionResult Forbidden()
        {
            return View();
        }

        public ActionResult InternalServerError()
        {
            return View();
        }

        public ActionResult NotFound()
        {
            return View();
        }

        public  ActionResult NotImplemented()
        {
            return View();
        }

        public ActionResult ServerBusyOrDown()
        {
            return View();
        }

        public ActionResult ServerUnavailable()
        {
            return View();
        }

        public ActionResult Timeout()
        {
            return View();
        }

        public ActionResult Unauthorized()
        {
            return View();
        }
    }
}

查看示例:

@{ 
    Layout = "~/Views/Shared/_FullWidthLayout.cshtml";
    ViewBag.Title = "404 Error";
}
<div class="opensans margin-sides text-center">
    <div class="text-center">
        <h1 class="text-normal">Uh oh! Something went wrong!</h1>
        <div class="img-container text-center">
            <div class="centered">
                <h1 class="bold">404 - Not Found</h1>
            </div>
            <img class="img text-center" src="~/Images/BackgroundImg.png" style="opacity: 0.15;" />
        </div>
        <p class="text-left">
            This is usually the result of a broken link, a web page that has been moved or deleted, or a mistyped URL.
            <ol class="text-left">
                <li>Check the URL you entered in the address bar for typos,</li>
                <li>If the address you entered is correct, the problem is on our end.</li>
                <li>Please check back later as the resource you requested could be getting worked on,</li>
                <li>However, if this continues for the resource you requested, please submit a <a href="mailto:EmailAddress?subject=Website%20Error">trouble ticket</a>.</li>
            </ol>
        </p>
    </div>
</div>

Web.Config 示例:

<customErrors mode="On" defaultRedirect="~/Error/Error">
  <!--The defaultRedirect page will display for any error not listed below.-->
  <error statusCode="400" redirect="~/Error/BadRequest"/>
  <error statusCode="401" redirect="~/Error/Unauthorized"/>
  <error statusCode="403" redirect="~/Error/Forbidden"/>
  <error statusCode="404" redirect="~/Error/NotFound"/>
  <error statusCode="408" redirect="~/Error/Timeout"/>
  <error statusCode="500" redirect="~/Error/InternalServerError"/>
  <error statusCode="501" redirect="~/Error/NotImplemented"/>
  <error statusCode="502" redirect="~/Error/ServerUnavailable"/>
  <error statusCode="503" redirect="~/Error/ServerBusyOrDown"/>
</customErrors>

就是这样!一步一步解决一个真正不应该成为问题的问题! 同样,您没有 CEP 的任何 statusCode 都将由 defaultRedirect 页面处理。

【讨论】:

  • 完美!我不明白为什么这个答案没有更多的赞成票。
【解决方案5】:

因为我遇到了一个非常相似的问题,所以我想进一步了解它。

customErrors 只会捕获在您的 ASP.NET 应用程序中抛出的实际 http 异常。虽然 HttpStatusCodeResult 不会引发异常。它只是使用相应的状态代码编写响应,这在您的示例中更有意义。

如果您在 IIS 7.0 或更高版本上运行,您现在应该使用 httpErrors,因为它会在所有情况下显示自定义错误页面。这是 IIS 级别设置。

我为此写了一篇完整的博客文章来解释这些差异: http://dusted.codes/demystifying-aspnet-mvc-5-error-pages-and-error-logging

【讨论】:

    【解决方案6】:

    更新

    您只需要针对 403 错误执行特殊重定向。所有其他 500 错误应通过 customErrors 中的 defaultRedirect="/Error/Error" 设置生效。但是,您需要删除或注释 App_Start/FilterConfig.cs 文件中的 HandleErrorAttribute 注册,自定义错误才能真正起作用。否则,该属性会将所有错误重定向到 Views/Shared 目录中的 Error.cshtml 文件。

    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            // remove this line below
            //filters.Add(new HandleErrorAttribute());
        }
    }
    

    原答案

    据我所知,由于某种原因,您不能在 web.config 中使用 customErrors 来处理 403 错误。我感觉到你的痛苦,因为它看起来应该像你已经拥有的代码一样简单,但显然 403 错误被视为 Web 服务器问题。

    您可以做的只是将用户重定向到您想要的“NoPermissions”页面,如下所示:

    public class CustomAuthorizeAttribute : AuthorizeAttribute
    {
        protected override void HandleUnauthorizedRequest(AuthorizationContext context)
        {
            if (context.HttpContext.Request.IsAuthenticated)
            {
                context.Result = new RedirectToRouteResult(new RouteValueDictionary(new
                {
                    action = "NoPermissions",
                    controller = "Error",
                    area = ""
                }));
            }
            else
            {
                base.HandleUnauthorizedRequest(context);
            }
        }
    }
    

    请求将具有 200 状态代码而不是 403,但如果您可以接受,这是一个简单的解决方法。

    这是一个类似的 SO 问题以获取更多信息:Returning custom errors

    另外,这篇文章解释了如何走 IIS 路线:http://kitsula.com/Article/MVC-Custom-Error-Pages

    【讨论】:

    • 那只适用于 403。那么 500 和其他代码呢?此外,httpErrors 也不适合我。
    • 我已更新我的答案以解决 500 问题。使用 httpErrors 时,请确保您实际上在 IIS 上。我不确定本地开发 Web 服务器 cassini 是否适用于 httpErrors。
    猜你喜欢
    • 2015-11-14
    • 2014-05-10
    • 1970-01-01
    • 1970-01-01
    • 2014-11-09
    • 2018-12-03
    • 2015-03-08
    • 2011-08-13
    • 1970-01-01
    相关资源
    最近更新 更多