Web.config system.web customErrors mode 错误页显示模式

6次阅读

customErrors mode=”on” 不拦截500错误是因为它仅处理404、403等客户端错误,未捕获的服务器异常(如空引用)默认由iis处理;需配合httperrors existingresponse=”passthrough”才能生效。

Web.config system.web customErrors mode 错误页显示模式

customErrors mode=”On” 为什么 500 错误还是显示黄页?

因为 mode="On" 只拦截 HTTP 404、403 等客户端错误,对未捕获的服务器异常(比如空引用、数据库连接失败)默认仍走 IIS 默认错误页——除非你同时配置了 defaultRedirect 且后端没抛出未处理异常到 IIS 层。

  • mode="On" 实际生效前提是:异常在 ASP.NET 管道内被 HttpApplication.Error 捕获,且未被 try/catch 吞掉或触发了 IIS 级崩溃(如 w3wp.exe 崩溃)
  • 常见漏网场景:Global.asax 中 Application_Error 里调用了 Server.ClearError() 却没做跳转;或者自定义 HTTP 模块抛出了未 handled 的异常
  • 验证方法:临时把 mode 改成 "Off",看是否真能显示详细——如果连 Off 都不显示,说明问题不在 customErrors,而在 IIS 的 httpErrorsstdoutLogEnabled

system.web customErrors 和 system.webServer httpErrors 冲突怎么办?

IIS 7+ 默认启用 httpErrors,它优先级高于 customErrors。当两者都配了 500 错误页,IIS 会直接返回 httpErrors 配置的页面,customErrors 彻底失效。

  • 开发环境建议关掉 httpErrors
    <system.webServer>   <httpErrors errorMode="Detailed" /> </system.webServer>
  • 生产环境若要用 customErrors,必须显式禁用 httpErrors
    <system.webServer>   <httpErrors existingResponse="PassThrough" /> </system.webServer>

    PassThrough 表示让 ASP.NET 自己决定响应内容)

  • 注意 existingResponse="Replace" 是默认值,它会强行用 httpErrors 覆盖所有响应,包括你代码里 Response.StatusCode = 500; Response.Write("xxx") 的手动输出

customErrors defaultRedirect 指向的页面为啥打不开?

不是路径写错,而是这个页面本身也触发了异常——比如 Error.aspx 里访问了 session,但此时 Session 已因原始错误被标记为不可用,导致二次 500,IIS 回退到默认黄页。

  • 错误页必须是静态 HTML 或纯 ASPX(无服务端控件、不依赖 Session / Application / 数据库)
  • 避免在错误页中调用 Server.GetLastError()——它在某些管道阶段已为空;改用 Context.AllErrors 更稳妥
  • 路径必须是应用根目录相对路径,比如 ~/error.html,不能写绝对 URL 或物理路径;~/ 开头才能被 ASP.NET 正确解析
  • 如果用了 URL 重写(如 IIS Rewrite Module),确保规则不干扰错误页请求(例如把 /error.html 也重写了)

mode=”RemoteOnly” 在本地测试时永远不生效?

因为 ASP.NET 判断“本地”的逻辑是:请求 IP 是否为 127.0.0.1::1,而不是看浏览器是否开在本机。用 localhost192.168.x.x、甚至 machine-name 访问,都会被当成远程请求,显示自定义页而非详细错误。

  • 调试时想强制看到详细错误,临时改成 mode="Off";上线前务必切回 "RemoteOnly""On"
  • 别信浏览器地址栏——用 curl -H "Host: yoursite.com" http://127.0.0.1/xxx 测试,才是真实模拟远程请求
  • 如果部署在反向代理后(如 nginx + IIS),RemoteOnly 可能失效,因为所有请求看起来都来自代理 IP;这时需在代理层加 X-forwarded-For 并在代码里手动判断来源

最常被忽略的是 httpErrorscustomErrors 的协作关系——它们不是互补,而是竞争。一个配错,另一个就形同虚设。调错顺序比写错页面路径更难排查。

text=ZqhQzanResources