.NET MVC HTTP错误自定义问题:自定义404页面不生效
.NET MVC 主动返回404状态码不显示自定义错误页的解决方法
问题描述
本地运行.NET MVC站点,自定义HTTP错误页面后,通过代码return new HttpStatusCodeResult(404);主动抛出404错误时,未显示预期的自定义错误页,而是出现HTTP默认错误页。相关配置代码如下:
global.asax 代码
protected void Application_Error(object sender, EventArgs e) { Exception exception = Server.GetLastError(); bool isAjaxRequest = Context.Request.Headers["X-Requested-With"] == "XMLHttpRequest"; if (!isAjaxRequest) { if (exception is HttpException httpException) { int httpCode = httpException.GetHttpCode(); if (httpCode == 404) { Response.Redirect("~/Error/NotFound"); } else if (httpCode == 500) { Response.Redirect("~/Error/ServerError"); } else { Response.Redirect("~/Error/Error"); } } else { Response.Redirect("~/Error/Error"); } } }
Web.Config 配置
<customErrors mode="On" defaultRedirect="/Error/Error"> <error statusCode="404" redirect="/Error/NotFound" /> <error statusCode="500" redirect="/Error/ServerError" /> </customErrors>
ErrorController 代码
public class ErrorController : Controller { [HttpGet] public ActionResult Error() { return View(); } [HttpGet] public ActionResult NotFound() { Response.StatusCode = 404; Response.TrySkipIisCustomErrors = true; return View(); } [HttpGet] public ActionResult ServerError() { Response.StatusCode = 500; Response.TrySkipIisCustomErrors = true; return View(); } }
问题原因
return new HttpStatusCodeResult(404)仅设置响应的HTTP状态码,不会抛出HttpException异常,因此Application_Error事件无法捕获该情况,也就不会跳转到自定义错误页。同时默认的customErrors配置在主动返回状态码的场景下,可能被IIS默认错误页覆盖。
解决方案
1. 修改Web.Config的customErrors配置
添加redirectMode="ResponseRewrite",避免通过跳转(302)返回错误页,确保响应状态码保持为原错误码(如404),同时让IIS优先使用自定义错误页:
<customErrors mode="On" defaultRedirect="/Error/Error" redirectMode="ResponseRewrite"> <error statusCode="404" redirect="/Error/NotFound" /> <error statusCode="500" redirect="/Error/ServerError" /> </customErrors>
2. 在global.asax中添加Application_EndRequest事件处理
用于捕获主动返回的HTTP错误状态码,并重写请求到对应的错误页面:
protected void Application_EndRequest() { var response = Context.Response; bool isAjaxRequest = Context.Request.Headers["X-Requested-With"] == "XMLHttpRequest"; // 只处理非Ajax、未跳转的错误状态码 if (!isAjaxRequest && response.StatusCode >= 400 && response.StatusCode < 600 && !response.IsRequestBeingRedirected) { Server.ClearError(); string errorPath = "/Error/Error"; switch (response.StatusCode) { case 404: errorPath = "/Error/NotFound"; break; case 500: errorPath = "/Error/ServerError"; break; } // 重写请求而非跳转,保留原状态码 Context.RewritePath(errorPath); IHttpHandler httpHandler = new MvcHttpHandler(); httpHandler.ProcessRequest(Context); } }
3. 优化Application_Error事件(可选)
原Response.Redirect会导致状态码变为302,可改为RewritePath保持原错误状态码:
protected void Application_Error(object sender, EventArgs e) { Exception exception = Server.GetLastError(); bool isAjaxRequest = Context.Request.Headers["X-Requested-With"] == "XMLHttpRequest"; if (!isAjaxRequest) { Server.ClearError(); string errorPath = "/Error/Error"; if (exception is HttpException httpException) { int httpCode = httpException.GetHttpCode(); switch (httpCode) { case 404: errorPath = "/Error/NotFound"; break; case 500: errorPath = "/Error/ServerError"; break; } } Context.RewritePath(errorPath); IHttpHandler httpHandler = new MvcHttpHandler(); httpHandler.ProcessRequest(Context); } }
关键说明
ResponseRewrite模式直接渲染错误页内容,不会发送跳转指令,能保留原HTTP状态码。Application_EndRequest会在每个请求结束时触发,可捕获所有未被Application_Error处理的主动返回错误状态码。Response.TrySkipIisCustomErrors = true必须保留在ErrorController的对应方法中,确保IIS不会覆盖自定义错误页。
内容的提问来源于stack exchange,提问作者krautcez
相关产品推荐
相关产品推荐

