customerrors在mvc中常失效,因其仅捕获asp.net管道内未处理的500类异常,而mvc控制器、模型绑定等环节异常会绕过它直入iis;且iis 7+默认启用httperrors,优先级更高,若未显式配置,将返回iis默认页而非自定义页。

生产环境直接暴露 Yellow Screen of Death(YSOD)是严重安全隐患,必须禁用;但仅靠 customErrors 配置无法覆盖所有异常场景,尤其 MVC 或 IIS 管道中未被捕获的 500 错误。
为什么 customErrors 在 MVC 中经常失效
ASP.NET Web Forms 的 customErrors 只拦截 ASP.NET 管道中抛出、且未被 try/catch 捕获的异常;而 MVC 的控制器执行、模型绑定、ActionFilter 等环节抛出的异常,会绕过该配置直接进入 IIS 层。此时即使 mode="On",用户仍可能看到原始堆栈或空白页。
-
customErrors不处理 HTTP 状态码为 404、403 的路由/静态资源错误,只管 500 类运行时异常 - MVC 中未在
Application_Error或GlobalFilters中捕获的异常,不会触发customErrors - IIS 7+ 默认启用自己的错误页机制(
httpErrors),会优先于customErrors生效
httpErrors 必须显式配置才能接管 500/404
在 web.config 的 <system.webserver></system.webserver> 节点下添加 httpErrors,否则 IIS 会返回自己的默认错误页(比如纯文本 “The resource cannot be found”),而不是你写的 /Error/NotFound。
<system.webserver><httperrors errormode="Custom" existingresponse="Replace"><remove statuscode="404"></remove><error statuscode="404" path="/Error/NotFound" responsemode="ExecuteURL"></error><remove statuscode="500"></remove><error statuscode="500" path="/Error/InternalServerError" responsemode="ExecuteURL"></error></httperrors></system.webserver>
-
responseMode="ExecuteURL"表示走 MVC 路由,能进ErrorController,可读取Server.GetLastError() -
existingResponse="Replace"强制覆盖 ASP.NET 已生成的响应体,避免出现“双重错误页” -
path值必须是绝对路径(如/Error/NotFound),不能带~/
Application_Error 是兜底关键,但别在里面 redirect
全局异常入口 Global.asax.cs 中的 Application_Error 方法能捕获所有未处理异常,但直接调用 Response.Redirect() 会导致状态码仍是 200,SEO 和监控工具会误判。
- 正确做法是:调用
Server.ClearError()清除异常,再设置Response.StatusCode = 500,然后用Server.TransferRequest()或路由方式跳转 - 若用 MVC,推荐构造
RouteData并手动执行ErrorController,这样视图里能拿到exception对象 - 注意:开发环境应保留原始错误页,可通过
HttpContext.Current.IsDebuggingEnabled判断是否跳转
自定义错误页返回正确状态码比“好看”更重要
很多开发者花时间美化 500.html 页面,却忽略一个致命问题:静态 HTML 错误页永远返回 200 状态码。搜索引擎和健康检查脚本会认为页面“正常”,掩盖真实故障。
- 动态错误页(如
ErrorController)必须显式设置Response.StatusCode,例如Response.StatusCode = 404 - 不要在
ErrorController.Index()中依赖Server.GetLastError()获取 404 异常——它通常为 null;应从路由或HttpContext中提取状态码 - 日志记录必须放在跳转前,否则
Server.ClearError()后就拿不到原始异常了
最易被忽略的是 httpErrors 和 customErrors 的共存逻辑:IIS 7+ 以上版本,httpErrors 优先级更高;若两者都配但路径不一致,生产环境实际生效的可能是你没测试过的那个。











