下午,同事顶着黑眼圈晃到我工位:"帮看看这个诡异问题。"
某个 Nuxt 3 静态站的移动端下载页:App Store 正常,Google Play 正常,唯独 "Direct APK Download" 按钮神秘消失。
更离谱的是环境分布——
| 环境 | APK 按钮 | 本地 dev | ✅ 有 | | 生产 | ✅ 有 | | Jenkins | ✅ 全绿 | | 测试 | ❌ 稳定复现 |
一时间怀疑人生:Nuxt 编译抽风?静态资源漏打包?CDN 缓存下毒?
这种"只在某个环境出现"的 Bug,最折磨人。我们这次让 Cursor Agent 跟着走了一遍排查,半小时把证据链串死了——结论先说:不是 AI 自动修好的,是 AI 帮咱们少走了很多弯路。
案发现场:三缺一,缺得很有纪律
同事原话"我明明手动上传了 apk.png 啊!OSS 里有的!"
(别急,这句话后面会回旋镖。)
页面现象很整齐:两个商店按钮在,APK 不在。不是偶发,是测试环境稳定复现。
当时大家怀疑的对象:
- Nuxt 编译是不是抽风了?
- 静态资源是不是漏打进包里?
- CDN 缓存是不是有毒?
- 是不是测试环境根本没部署最新构建?
传统排查的话,这套流程能折腾一整天:全局搜 apk、本地 generate、diff .output、curl HTML、登 OSS、翻 Jenkins……前端和运维容易互相甩锅。
先别在错的文件里加班
同事一开始盯的是 components/download/index.vue。
Agent 在仓库里语义搜了一圈:截图里的页面其实是 `/mobile/downLoad`,对应 pages/mobile/downLoad.vue。
而且 APK 按钮是直接渲染的——没有 v-if,没有权限分支,没有"仅 iOS 显示"那套。
代码侧:Vue 无罪
顺着真页面往下看,逻辑很直白:三个下载入口并排,APK 没被谁藏起来。
所以"按钮被条件渲染吃掉"这条线,可以当场划掉。
构建侧:本地 generate 也没翻车
本地跑 npm run generate,翻 .output/public/_nuxt/:
构建产物里有 apk.CsrglTfa.png——图打进包了,hash 也正常。
于是再划掉一批经典甩锅:
- 代码没提交
- 资源没打包
- Vue 构建异常
问题开始往 "部署之后,运行时拿到的资源不对" 收敛。
线上取证:curl 不会跟你客气
接下来是整案最关键的一步:别猜,去拉测试环境和生产的 HTML、JS chunk。
# 示意:拉页面引用的 chunk,搜 apk 相关字符串
curl -s "https://test.example.com/mobile/downLoad" | grep -o '_nuxt/[^"]*\.js'
curl -s "https://test.example.com/_nuxt/xxxxx.js" | grep -i "apk"对比结果很干脆:
| 对比项 | 测试环境 | 生产环境 | | --- | --- | --- | | chunk 里是否有 jegotrip.apk 相关引用 | ❌ 没有 | ✅ 有 | | 推断 | 跑的像旧构建或未完整部署 | 与当前构建一致 |
到这里,锅已经不太像"前端写错一行"了。
OSS 截图一锤定音
同事发来 OSS 控制台:NoSuchKey。
请求路径:
/_nuxt/apk.CsrglTfa.png
他坚持:"我上传了 apk.png 啊!"
全场安静了两秒。
真凶:hash 文件名和 OSS 上的 Key 不是一回事
Vite / Nuxt 会给静态资源加 content hash:
源码里引用:apk.png
构建后文件名:apk.CsrglTfa.png
页面运行时请求:/_nuxt/apk.CsrglTfa.png而 OSS 上实际存在的,往往是同事手工补的:
apk.png(无 hash,路径还可能不在 _nuxt/)
浏览器按 HTML/JS 里的 hash 名去要文件 → OSS 说没有 → 图片 404 → 按钮看起来就像"消失"了(其实是图挂了,整块 UI 塌了或样式把空图藏了)。
Jenkins 全绿,为啥还能翻车?
这是很多团队的真实误区:
CI Success ≠ Runtime Resource Integrity
Jenkins 绿灯通常只说明:
- 构建脚本执行成功
- 流水线没报错退出
不保证:
- OSS 已整包同步
- CDN 已刷新
- 没人往桶里手工塞错文件名的"救急包"
- 多节点、多路径资源一致
所以"构建成功 + 测试环境缺按钮"完全可以同时成立。
这次 Agent 到底帮了啥忙?
别把它想成"自动修 Bug 神器"。这次有用的三件事:
- 快速收窄范围——Vue 逻辑、条件渲染、本地构建,很快排除;少刷无效 PR 和无效会议。
- 跨层串线索——页面路由 → chunk 引用 → hash 文件名 → OSS Key → 404,一条链拉通;单靠"我只看前端"很难这么快对齐。
- 用证据代替吵架——curl 结果、chunk 对比、NoSuchKey 路径,甩群里比"我觉得你没上传"管用一万倍。
它更像一个不会累、还肯帮你跑命令的排障搭子——最后拍板的还是人。
四条血泪建议(建议贴发布 checklist)
- 别只信 CI 绿灯——上线后自动探活:关键 HTML、关键 JS、关键静态资源 URL 返回 200,才算真成功。
- 静态资源整包同步——Nuxt generate 后,同步整个
.output/public/,别只传 JS/CSS,更别漏_nuxt/里带 hash 的图。 - 别往 OSS 根目录手工补"同名无 hash"文件——现代前端认 hash,你补
apk.png救不了apk.CsrglTfa.png的 404。 - 把资源一致性校验写进发布——HTML 引用的每个
_nuxt/*资源,部署后脚本扫一遍可访问性;很多团队缺的就是这一环。
以前总觉得这种"环境灵异 Bug"靠老司机嗅觉。
这次更大的感受是:所谓玄学,多半只是缺一条完整证据链。
Agent 擅长的,就是把散落各处的线索——仓库路径、构建目录、curl 输出、OSS 报错——收敛成一个能验证、能复现、能写进复盘的故事。
修可能还是人修;少绕路、少背错锅、少开无效会,就已经很值了。
我端起杯子——冰美式早凉了,但测试环境的 APK 按钮,总算在 OSS 里找到了它该有的 hash 文件名。
发表评论
分享你的想法和反馈