MVC项目发布到服务器后路由打不开,多数时候问题不在代码,而在三层:IIS的托管管道模式、web.config里的Handler节点、以及域名到站点之间的那层转发规则。 把这三处对齐,本地F5能跑的URL,线上一样能跑。
本地能跑、传到服务器路由就失效,问题出在哪
这个场景几乎每个做.NET的人都遇到过:Visual Studio里调试一切正常,FTP把发布包传上去,首页能打开,点进列表页直接404,带参数的URL刷新一下变500,人一下子就懵了,代码一个字没改,怎么就坏了。
原因很朴素本地跑的是IIS Express或者Visual Studio自带的那套宿主,它默认就把无扩展名的URL交给ASP.NET处理了,而服务器上的IIS是一台“干净”的机器,它不知道.html之外的路径该给谁,请求进来,IIS先判断:这是个文件吗?不是,是个目录吗?不是,那我返回404。
所以路由配置的本质,是告诉服务器“这个URL不是文件,请转交给应用程序处理”,搞清这一点,后面所有操作都有据可依。
常见的失效表现可以对照着看:
- 首页能开,二级页面404 九成是应用程序池的托管管道模式不对
- 页面能开,带
?id=3这类参数刷新报错 路由约束或参数绑定问题 - 静态资源正常,所有动态路径都挂 缺少无扩展名Handler
- 内网访问正常,外网域名访问404 站点绑定或反向代理层没转发
MVC项目发布到服务器后路由404怎么解决
按顺序排查,别跳步,跳步最容易在中间某个环节绕圈。
第一步:确认请求到底停在哪一层
先在服务器上打开浏览器,用http://localhost/你的路径访问,如果本机通、外网不通,问题在绑定或防火墙;如果本机也不通,问题在IIS配置,这一步能砍掉一半的排查范围。
顺手看一眼IIS的“处理程序映射”里有没有ExtensionlessUrlHandler-Integrated-4.0这一项,没有就是组件缺失。
第二步:应用程序池必须是集成模式
打开IIS管理器,左侧点“应用程序池”,找到你站点用的那个池,右键“基本设置”:
- .NET CLR版本选 v4.0(对应.NET Framework 4.x项目)
- 托管管道模式选 集成
经典模式(Classic)下,无扩展名请求默认不经过ASP.NET,路由必然失效这是出现频率最高的一个坑,改完记得回收应用程序池,光点“确定”有时不生效。
查池状态可以用命令行,比点鼠标快:
%windir%\system32\inetsrv\appcmd list apppool
第三步:web.config里两个节点不能删
发布包里自带的web.config,system.webServer节点下这两块是关键,缺一个路由就断:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0"
path="."
verb=""
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
runAllManagedModulesForAllRequests="true"让所有请求都过一遍托管模块,ExtensionlessUrlHandler负责把无扩展名路径交给MVC,很多教程让人把这段删掉“减少开销”,结果路由就废了,要优化性能,正确做法是加条件放行,而不是一刀切删掉。
如果服务器上压根没有URL Rewrite模块,去微软官方站点下载安装,装完重启IIS,顺便说一句,这个模块不是路由的必需品,但很多项目用它做强制HTTPS跳转,缺了会连带出别的问题。
第四步:RouteConfig的默认路由别乱改
App_Start/RouteConfig.cs里这段是标准写法:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
要检查两点:Global.asax里确实调用了RouteConfig.RegisterRoutes,以及路由注册顺序越具体的路由越要写在前面,被通用路由抢先匹配就再也轮不到它。
第五步:静态文件别被路由吃掉
Web.config的modules里加一条忽略规则,或者把静态资源放到独立目录并在IIS里设为应用程序,否则图片、CSS请求会被当成控制器名去匹配,日志里全是404。
MVC路由配置和IIS重写规则哪个好
这个问题在技术群里隔三差五就有人问,两者不是替代关系,得看你解决的是什么问题。
| 对比项 | 框架内置路由 | IIS URL Rewrite |
|---|---|---|
| 作用位置 | 应用内部,请求已进入ASP.NET | 服务器层,请求还没到应用 |
| 典型用途 | 控制器/动作映射、参数绑定 | 伪静态、强制HTTPS、老URL重定向 |
| 性能开销 | 极小,纯内存匹配 | 每条规则一次正则,规则多时有感 |
| 调试难度 | 有路由调试工具,相对直观 | 日志在IIS里,排查链路长 |
| 适合场景 | 新项目、RESTful风格接口 | 老站改版保URL、GEO跳转 |
行业共识认为,新项目的路径映射优先用框架路由,重写模块只做路由干不了的事,比如把/old-article-123.html永久跳到/article/123,这种事交给IIS最省心;而/product/detail/5这种映射,写在代码里更好维护。
两者叠加时注意顺序:IIS重写先执行,改完的URL再进应用路由,调试时要分开看日志,别混在一起猜。
简米云服务器部署MVC站点路由怎么配
云服务器和自建机房最大的差别,是流量进机器之前还有一道安全组,路由配得再对,80端口没放行也是白搭。
域名绑定与端口放行
按这个顺序走:
- 在云控制台的安全组入方向,放行80和443(Web)端口,需要远程调试再单独放行3389
- IIS里新建站点,绑定域名,物理路径指向发布目录
- 域名解析到公网IP,等生效
- 服务器本地用
localhost测一遍,再测域名
华北2(北京)、华东1(杭州)这些常用节点的安全组默认规则不完全一样,换地域部署时建议重新核对一遍,别照搬旧配置。
前面挂了Nginx的情况
不少项目在IIS前面再加一层Nginx做负载和HTTPS卸载,这时候请求转给IIS,路径里可能多出前缀,路由就会全错,解决方案二选一:Nginx里proxy_pass末尾带不带斜杠要统一,或者在IIS里把站点配成应用程序并设好虚拟路径。
Spring MVC、Laravel这类项目挂在Nginx上,思路相同,靠一条try_files兜底:
location / {
try_files $uri $uri/ /index.php?$query_string;
}
ASP.NET Core则要确认Program.cs里app.UseRouting()在UseAuthorization()之前,顺序错了路由表是空的。
自己配还是花钱找人配
一台2核4G的入门云服务器,一年花费大概在几百到一千多元区间,具体看带宽和地域,路由配置本身不额外收费,属于部署环节的一部分,如果你找服务商代做,市面上的报价从几十元到几百元不等,差别主要在是否包含SSL证书、域名备案协助和后续排障,坦白讲,看完这篇文章,自己动手的时间成本也就是半小时到一个小时,比沟通需求还快。
路由配置里最容易踩的五个坑
- 发布时没勾选“删除目标位置的其他文件”,旧web.config残留,新配置不生效
- 改了配置没回收应用程序池,IIS有缓存,看起来像没保存
- 控制器名拼写和路由大小写不一致,Windows下不报错,换Linux容器立刻挂
- 路由约束写太死,
{id:int}遇到空值直接404 - 多站点共用应用程序池,一个站点崩溃全部陪葬
关于MVC发布到服务器路由配置的常见问题
问:本地一切正常,发布到服务器后路由全404,最快怎么定位?
答:先看应用程序池是不是集成模式,这是命中率最高的一项,其次检查web.config里ExtensionlessUrlHandler和runAllManagedModulesForAllRequests是否还在,两项都没问题,再打开IIS的失败请求跟踪,看请求在哪一步被拦下。
问:MVC路由配置需要额外装什么组件吗?
答:IIS里需要“ASP.NET”和“ISAPI扩展”两个功能,安装.NET Framework 4.x后自动带上,URL Rewrite模块是可选的,只在需要伪静态或跳转时安装,如果项目是ASP.NET Core,要装的是Hosting Bundle,且安装后必须执行net stop was /y再启动,否则模块不注册。
问:路由配好了,但带参数的URL分享给别人打不开,是什么情况?
答:多数是前端用了History模式但服务端没配兜底规则,用户直接在浏览器里刷新或粘贴URL,请求落到服务器上一个不存在的物理路径,在IIS里加一条重写到/index.html的规则,或者在应用路由里补一条捕获所有路径的默认路由即可。
把MVC项目推上服务器,路由配置从来不是“写完就完事”的一步,它是应用和服务器之间的一份约定,约定写清楚了,本地和线上就没有差别,下次再遇到404,先别急着翻代码,去IIS里看一眼那个应用程序池。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/772419.html


