孝感实诚网络科技有限公司 · 实诚科技 · 湖北孝感

宝塔 + IIS 部署 .NET 应用的六个坑:应用池回收、静态文件、路由冲突

2026-11-07 · 实诚科技 · 孝感实诚网络科技有限公司

我们的生产环境是 Windows Server + 宝塔面板 + IIS,跑 .NET 9 的 Web API 加 Vue 打包后的静态文件。部署流程看起来很简单:编译、上传、回收应用池。但这两年踩过的坑足够写一篇。 坑一:应用池定时回收导致定时任务漏跑 IIS 应用池默认有「闲置超时」和「定时回收」策略,回收的瞬间正在执行的后台任务会被打断。我们的每日自动写稿任务设在 8:00,而应用池的回收时间也是 8:00 附近,结果连续几天没有生成文章,日志里什么都没有。 解法有两层: 把应用池的回收时间挪开业务高峰(比如凌晨 4 点),并设置 Disable Overlapped Recycle = false ,让新旧进程平滑切换; 在应用启动时做补偿:检查「今天是否已执行」,没执行就立刻补跑一次。这比依赖定时器可靠得多。 // 启动补偿:过了执行时间但今天没跑过,就补一次 if (DateTime.Now.TimeOfDay > targetTime && lastRunDate != DateTime.Today) { await GenerateDailyAsync(force: false); } 坑二:静态文件被路由吃掉 Vue 打包后的文件在 wwwroot ,理论上 UseStaticFiles() 就能访问。但我们的 SPA fallback 写了「所有未匹配路由都返回 index.html」,结果 /assets/index-abc.js 也返回了 HTML,浏览器报 MIME 错误。 原因是 MapFallbackToFile 在静态文件中间件之后注册才有效。正确顺序: app.UseStaticFiles(); // 先 app.UseRouting(); app.MapControllers(); app.MapFallback(...); // 最后 另一个相关坑:上传目录 /uploads 如果是运行时创建的,IIS 进程需要有写权限。宝塔默认的应用池账户可能没有,表现为上传返回 500,日志里是 UnauthorizedAccessException 。 坑三:同时注册 /tools 和 /tools/ 导致 500 我们给工具页注册了两条路由,想同时支持带斜杠和不带斜杠。结果访问直接 500,响应体是空的,日志里是 AmbiguousMatchException 。 ASP.NET Core 的路由匹配对尾斜杠是宽容的,注册一条就够: app.MapGet("/tools", handler); // /tools/ 也会命中 // app.MapGet("/tools/", handler); ← 删掉 这类问题最难查,因为浏览器只显示 500,没有任何提示。建议在任何 MapGet 外面包一层 try-catch,把异常写进响应体,至少在调试阶段能看见。 坑四:EF Core 的默认值把开关吃掉了 给 is_show 字段配了 HasDefaultValue((byte)1) ,结果后台把开关关掉(传 0),入库还是 1。 原因是 EF Core 把「CLR 默认值」当作「未赋值」的标记: byte 的默认值是 0,所以传 0 时 EF 认为你没赋值,改用数据库默认值。 解法是不要给这种布尔语义字段配数据库默认值,改在实体初始化器里给: public byte IsShow { get; set; } = 1; // 而不是 HasDefaultValue(1) 坑五:HTTPS 重定向死循环 在 IIS 里配了强制 HTTPS,同时在应用里也写了 UseHttpsRedirection() ,结果部分请求 302 循环。 原因是 IIS 层面的重写规则和应用层的重定向互相不认识,尤其是反向代理场景下,应用看到的 scheme 是 http ,于是又重定向一次。 解法:只在一层做重定向。要么 IIS 做(推荐,性能好),要么应用做并正确配置 ForwardedHeaders : app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }); 坑六:部署后「没生效」的假象 这个坑最耗时间。改完代码、上传 dll、回收应用池,打开页面还是旧的。原因是: 浏览器缓存了 HTML 和 JS; CDN 缓存了 HTML; 应用池回收需要几秒,请求打到旧进程; dll 被进程占用,上传实际失败了但脚本没报错。 现在的部署脚本会做四件事:上传前校验文件大小、上传后比对远程文件时间戳、回收应用池后轮询等待新进程 PID、最后用带 no-cache 头的请求验证关键页面。 # 验证时一定要带这个头,否则测的是缓存 curl -H "Cache-Control: no-cache" https://example.com/ 一份部署检查清单 编译产物是否包含所有依赖 dll(尤其是新加的项目引用); 应用池是否已回收,worker 进程 PID 是否变化; 静态文件目录是否有写权限; appsettings 的连接串、密钥是否与目标环境一致; 关键页面是否 200,且返回的是新内容; 日志目录是否可写,有没有异常堆积。 部署这件事,做对一百次没人知道,做错一次所有人都知道。清单化比记性可靠。

孝感实诚网络科技有限公司(实诚科技)专注网站建设、小程序开发、管理系统定制与软件工具开发,咨询热线 13622369854。

新闻资讯列表联系我们
孝感实诚网络科技有限公司 · 咨询热线 13622369854 · 微信 Ae77056 · 邮箱 admin@shichenkeji.com
湖北省孝感市孝南区城站路泰阳城

孝感实诚网络科技有限公司(实诚科技 · 实诚网络)

孝感实诚网络科技有限公司(品牌简称「实诚科技」、「实诚网络」,官网 shichenkeji.com)位于湖北省孝感市孝南区,是一家专注企业数字化服务的技术公司。核心团队平均 8 年以上开发经验,10 年技术沉淀,已为 600+ 家企业提供服务,累计交付 1200+ 项目。

主营业务

联系方式

关于实诚科技 · 自研产品 · 网站模板 · 项目案例 · 新闻资讯 · 联系我们