ASP.NET MVC(非.NET Core无Startup.cs)如何实现保留原始错误URL的404页面
非.NET Core MVC 保留原始URL的404 Razor页实现方案
问题根因
你遇到的aspxerrorpath参数、跳转后URL丢失原始路径的问题,本质是web.config里customErrors默认使用了ResponseRedirect模式:这个模式会强制触发客户端跳转,跳转前ASP.NET自动把原始错误路径拼接到查询串上,同时浏览器地址栏会被改成错误页的地址,完全无法满足GA采集原始错误URL的需求。
第一步:调整customErrors配置,放弃客户端跳转
直接把customErrors的redirectMode改成ResponseRewrite,这个模式不会触发任何客户端跳转,服务端会在当前请求的上下文中直接执行错误页的内容,浏览器地址栏会一直保留用户输入的原始错误URL,从根源上避免跳转和参数拼接。
在<system.web>节点下加入如下配置:
<customErrors mode="RemoteOnly" defaultRedirect="~/Error/ServerError" redirectMode="ResponseRewrite"> <error statusCode="404" redirect="~/Error/NotFound" /> <error statusCode="500" redirect="~/Error/ServerError" /> </customErrors>
第二步:接管IIS层的错误请求
很多时候即使配了customErrors,访问不存在的静态文件、未匹配MVC路由的请求还是会被IIS拦截,返回IIS自带的默认错误页,这是因为IIS的httpErrors模块优先级高于ASP.NET管线的配置,需要同步调整:
在<system.webServer>节点下加入如下配置:
<httpErrors errorMode="Custom" existingResponse="PassThrough"> <remove statusCode="404" subStatusCode="-1" /> <error statusCode="404" subStatusCode="-1" responseMode="ExecuteURL" path="~/Error/NotFound" /> </httpErrors>
参数说明:
existingResponse="PassThrough":如果ASP.NET已经输出了错误响应内容,IIS不做覆盖responseMode="ExecuteURL":服务端直接执行错误地址的内容,不做客户端跳转,保证地址栏不变
第三步:实现MVC端的Error控制器
新建位于根控制器目录下的ErrorController,不要加授权过滤器、自定义路由约束,保证未匹配全局路由的请求也能正常访问对应的Action:
public class ErrorController : Controller { public ActionResult NotFound() { // 手动设置404状态码,服务端重写模式下默认响应是200 Response.StatusCode = 404; // *这个属性必须加,否则IIS会检测到404状态码,自动把你写的视图替换成IIS自带的错误页* Response.TrySkipIisCustomErrors = true; return View(); } public ActionResult ServerError() { Response.StatusCode = 500; Response.TrySkipIisCustomErrors = true; return View(); } }
后续在对应视图目录下建NotFound.cshtml、ServerError.cshtml的Razor视图就可以正常渲染了。
效果验证
按照上述配置完成后:
- 用户输入任意不存在的URL(比如
http://localhost/adadasd),浏览器地址栏会始终显示这个原始地址,不会跳转到/error路径,也不会附带任何aspxerrorpath参数 - 页面正常加载你写的Razor版错误视图
- 响应返回标准404/500状态码
- Google Analytics采集到的页面路径就是用户实际输入的错误URL,完全满足错误访问数据的统计需求
常见踩坑点
- 不要把redirectMode改回
ResponseRedirect,只要用这个模式,ASP.NET就会强制拼接aspxerrorpath参数,丢失原始URL - 不要把Error控制器放在Area目录下,未匹配路由的请求走全局路由规则时,找不到Area内的控制器
- 测试时要覆盖静态路径(比如/test.jpg、/api/xxx)场景,确保所有未找到的请求都能走到Razor错误页
内容的提问来源于stack exchange,提问作者Andrey Lima Ramos
相关产品推荐
相关产品推荐

