我有一个MVC 4应用程序,使用自定义HandleErrorAttribute来处理自定义异常。我想拦截默认的404和其他非500错误页面,并用更具吸引力的东西替换它们。为此,我将以下内容添加到我的Web.config:
<system.web>
<customErrors mode="On" defaultRedirect="~/Error/Index" />
...
</ system.web>
我有一个带有索引方法和相应视图的错误控制器,但我仍然得到默认的404错误页面。我也尝试将我的defaultRedirect
设置为静态html文件无效。我已经尝试在<customErrors>
内添加特定于404的错误处理,我甚至尝试以编程方式修改路由,所有这些都没有结果。我错过了什么?为什么ASP忽略了我的默认错误处理?
注意:我之前注意到我无法在本地测试我的CustomHandleErrorAttribute,即使使用<customErrors mode="On"
也是如此。当我在我的服务器上从我的开发盒中点击它时它确实有效...不确定这是否相关。 This guy遇到了同样的问题。
答案 0 :(得分:14)
这应该有效:
<强> 1。 Web.Config中强>
<customErrors mode="On"
defaultRedirect="~/Views/Shared/Error.cshtml">
<error statusCode="403"
redirect="~/Views/Shared/UnauthorizedAccess.cshtml" />
<error statusCode="404"
redirect="~/Views/Shared/FileNotFound.cshtml" />
</customErrors>
<强> 2。将FilterleErrorAttribute注册为FilterConfig类中的全局操作过滤器,如下所示
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CustomHandleErrorAttribute());
filters.Add(new AuthorizeAttribute());
}
如果那不起作用,请尝试通过检查状态代码(例如Global.asax中的以下内容)来转移响应:至少它必须有效。
void Application_EndRequest(object sender, EventArgs e)
{
if (Response.StatusCode == 401)
{
Response.ClearContent();
Server.Transfer("~/Views/Shared/UnauthorizedAccess.cshtml");
}
}
答案 1 :(得分:6)
我的主题很少。我认为解释这一点非常重要。
如果你注意上面突出显示的部分。我已经指定了Action Filter的顺序。这基本上描述了Action Filter的执行顺序。当您通过Controller / Action Method
实现多个Action Filters时,就会出现这种情况
这张图片只是表明你有两个动作过滤器。 OnActionExecution
将开始执行优先级,OnActionExecuted
将从底部开始到顶部。这意味着如果OnActionExecuted
动作过滤器具有最高顺序将首先执行,而在OnActionExecuting
动作过滤器具有最低顺序将首先执行。以下示例。
public class Filter1 : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//执行将从这里开始 - 1
base.OnActionExecuting(filterContext);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//执行将移至此处 - 5
base.OnActionExecuted(filterContext);
}
}
public class Filter2 : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//执行将移至此处 - 2
base.OnActionExecuting(filterContext);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//执行将移至此处 - 4
base.OnActionExecuted(filterContext);
}
}
[HandleError]
public class HomeController : Controller
{
[Filter1(Order = 1)]
[Filter2(Order = 2)]
public ActionResult Index()
{
//执行将移至此处 - 3
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
}
您可能已经意识到MVC框架中有不同类型的过滤器。它们列在下面。
授权过滤器
动作过滤器
响应/结果过滤器
异常过滤器
在每个过滤器中,您可以指定Order属性。这基本上描述了动作过滤器的执行顺序。
这适合我。这非常简单,无需考虑Web.Config中的任何更改或在Global.asax文件中注册Action Filter。
确定。所以,首先我要创建一个简单的动作过滤器。这将处理Ajax和非Ajax请求。
public class MyCustomErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
var debugModeMsg = filterContext.HttpContext.IsDebuggingEnabled
? filterContext.Exception.Message +
"\n" +
filterContext.Exception.StackTrace
: "Your error message";
// 当您需要处理Ajax请求
时就是这种情况 if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.Result = new JsonResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new
{
error = true,
message = debugModeMsg
}
};
}
// 处理非Ajax请求时的情况
else
{
var routeData = new RouteData();
routeData.Values["controller"] = "Error";
routeData.Values["action"] = "Error";
routeData.DataTokens["area"] = "app";
routeData.Values["exception"] = debugModeMsg;
IController errorsController = new ErrorController();
var exception = HttpContext.Current.Server.GetLastError();
var httpException = exception as HttpException;
if (httpException != null)
{
Response.StatusCode = httpException.GetHttpCode();
switch (System.Web.HttpContext.Current.Response.StatusCode)
{
case 404:
routeData.Values["action"] = "Http404";
break;
}
}
var rc = new RequestContext
(
new HttpContextWrapper(HttpContext.Current),
routeData
);
errorsController.Execute(rc);
}
base.OnException(filterContext);
}
}
现在,您可以在Controller上以及仅在Action上实现此Action Filter。示例:
希望这对你有所帮助。
答案 2 :(得分:0)
创建一个Controller ErrorController。
public class ErrorController : Controller
{
//
// GET: /Error/
public ActionResult Index()
{
return View();
}
}
为操作创建索引视图。
<。>在Web.config中<customErrors mode="On">
<error statusCode="404" redirect="Error/Index"/>
</customErrors>
当您处理代码/逻辑中的错误时
[HandleError]
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Modify this template to jump-start application.";
return View("Index2");
}
}
[HandleError]属性 - 将重定向到共享文件夹内的Error.cshtml页面。
答案 3 :(得分:0)
我不确定这个答案是否会对您有所帮助,但这只是一个简单的方法...我将/中的error.html设置为on并在Web配置中将自定义错误设置为on,这非常有效......
<system.web>
<customErrors defaultRedirect="~/Error.html" mode="On" />
</system.web>
这个error.html是一个带头部和身体的基本html页面。
答案 4 :(得分:0)
在调查此问题后,我想分享我的知识。欢迎任何有助于改善我的陈述的评论。
在ASP.NET MVC中,三层按以下顺序处理HTTP请求(响应以相反的顺序进行传输):
IIS(HTTP层)
ASP.NET(服务器层)
控制器(MVC层)
所有这些层都有错误处理,但是每个层的处理方式不同。我将从IIS开始。
IIS如何处理错误的最简单示例是使用浏览器从服务器请求不存在的.html文件。地址应如下所示:
http://localhost:50123/this_does_not_exist.html
注意浏览器选项卡的标题,例如: IIS 10.0详细错误-404.0-未找到。
当IIS收到HTTP请求时,如果URL以.aspx结尾,则将其转发到ASP.NET,因为它已注册为处理此扩展名。 ASP.NET如何处理错误的最简单示例是使用浏览器从服务器请求不存在的.aspx文件。地址应如下所示:
http://localhost:50123/this_does_not_exist.aspx
请注意页面底部显示的版本信息,表示ASP.NET的版本。
customErrors 标签最初是为ASP.NET创建的。当响应由ASP.NET内部代码创建时,它仅有效。这意味着它不会影响从应用程序代码创建的响应。此外,如果ASP.NET返回的响应不包含任何内容,并且具有错误状态代码(4xx或5xx),则IIS将根据状态代码替换响应。我将提供一些示例。
如果Page_Load方法包含Response.StatusCode = 404
,则内容将正常显示。如果添加了附加代码Response.SuppressContent = true
,则IIS以与请求“ this_does_not_exist.html”时相同的方式进行干预并处理404错误。没有内容和状态代码2xx的ASP.NET响应不受影响。
当ASP.NET无法使用应用程序代码完成请求时,它将使用内部代码处理该请求。请参阅以下示例。
如果无法解析URL,ASP.NET会自行生成一个响应。默认情况下,它将使用包含有关问题的详细信息的HTML正文创建404响应。可以使用customErrors来创建302(重定向)响应。但是,访问导致ASP.NET返回404响应的有效URL不会触发customErrors指定的重定向。
当ASP.NET从应用程序代码捕获异常时,也会发生同样的情况。默认情况下,它使用HTML主体创建500响应,其中包含有关引起异常的源代码的详细信息。同样,customErrors可代替生成302(重定向)响应。但是,从应用程序代码创建500响应不会触发customErrors指定的重定向。
defaultRedirect 和 error 标签非常直观,可以理解我刚才所说的内容。错误标记用于为特定状态码指定重定向。如果没有相应的错误标记,则将使用defaultRedirect。重定向URL可以指向服务器可以处理的任何内容,包括控制器操作。
使用ASP.NET MVC,事情变得更加复杂。首先,可能有两个“ Web.config”文件,一个在根目录中,一个在Views文件夹中。我想指出,Views的默认“ Web.config”对此线程有两件有趣的事情:
对于ASP.NET MVC,可以将 HandleErrorAttribute 添加到GlobalFilters,这还考虑了 mode 属性的值。来自根“ Web.config”的customErrors标记。更具体地说,当该设置为On时,它将启用MVC层中针对控制器/操作代码中未捕获的异常的错误处理。而不是将它们转发到ASP.NET,它默认情况下呈现Views / Shared / Error.cshtml。可以通过设置HandleErrorAttribute的View属性来更改。
基于请求URL,在控制器/操作解决后,MVC层开始进行错误处理。例如,在MVC层处理不满足操作参数的请求。但是,如果POST请求没有匹配的控制器/动作可以处理POST,则该错误将在ASP.NET层处理。
我已使用ASP.NET MVC 5进行测试。 IIS和IIS Express在错误处理方面似乎没有什么区别。
我能想到为什么不为非500状态代码不考虑customErrors的唯一原因是因为它们是使用HttpStatusCodeResponse创建的。在这种情况下,响应是由应用程序代码创建的,而不是由ASP.NET处理,而是由IIS处理。此时,配置备用页面是没有意义的。这是重现此行为的示例代码:
public ActionResult Unhandled404Error()
{
return new HttpStatusCodeResult(HttpStatusCode.NotFound);
}
在这种情况下,我建议实现一个ActionFilterAttribute,它将覆盖OnResultExecuted
并执行以下操作:
int statusCode = filterContext.HttpContext.Response.StatusCode;
if(statusCode >= 400)
{
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.Redirect("/Home/Index");
}
已实现的ActionFilterAttribute应该添加到GlobalFilters。
答案 5 :(得分:0)
对我来说,它可以删除默认的Error.cshtml文件,现在它将使用Web.config中的自定义Error defaultRedirect页面。