线上报错怎样用 Source Map 还原,又不把 map 文件公开?
构建时生成不带 sourceMappingURL 注释的 hidden source map,按发布版本上传到错误监控服务或内网存储,部署产物中删除 .map;上报原始堆栈后由服务端根据版本和文件名还原到源码位置。
参考答案
简答
- 浏览器通过
//# sourceMappingURL=注释或SourceMap响应头找到 map;按 ECMA-426,两者都有时以响应头为准。 - 生产环境用 hidden source map:照常生成
.map,但产物里不写引用注释,浏览器不会自动加载。 .map只上传到错误监控服务或内网存储,部署到静态托管前从产物目录删除;没有注释不等于安全,文件留在服务器上仍可被猜路径下载。- 还原在服务端进行:前端上报原始堆栈和发布版本号,服务端按版本找到对应 map,把压缩后的行列号映射回源码位置。
为什么不公开 map
Source Map 的原理、sourcesContent 会暴露源码、按版本上传的基本流程,见《Source Map 如何帮助定位压缩后代码的错误?》。本题只讲监控侧的取舍。
nosources-source-map 不含源码内容,只保留映射,可以部署;监控平台还原出的是源文件名和行列号,看不到源码片段,文件名和目录结构仍会暴露。要在告警里直接看到出错代码,就只能用含源码的 hidden map,并且不部署。
构建配置
JavaScript
// webpack.config.js
export default {
mode: 'production',
devtool: 'hidden-source-map',
};
JavaScript
// vite.config.js
export default {
build: { sourcemap: 'hidden' },
};
Vite 的 'hidden' 与 true 一样输出独立 map 文件,只是去掉产物里的注释。
版本必须一一对应
前端 SDK 上报的版本号要与上传 map 时的版本号相同(如 Git 提交哈希)。同名文件在不同构建中内容不同时,用错 map 会还原出看似合理却错误的行;文件名带内容哈希能降低这类风险。部署前从 dist 删除 *.map,没有注释不等于安全,留在服务器上的文件仍可被猜路径下载。
还原过程
上报的堆栈形如 at a (https://cdn.example.com/app.3f2a.js:1:20345)。服务端按版本和文件 URL 找到对应 map,用 source-map 类库查询第 1 行第 20345 列,得到源文件、原始行列和函数名。
前提是上报了原始 error.stack。跨域脚本只剩 Script error. 时没有行列号,还原无从谈起,需要先解决跨域问题,见《前端怎样全局捕获 JS 错误、Promise 拒绝和资源加载失败?》。
常见追问
- 调试线上问题时开发者能看源码吗?可以在 DevTools 中手动关联本地或内网的 map 文件,不需要公开。
- 第三方库的报错能还原吗?只要构建时生成的 map 包含这些模块就能;未打包的外部 CDN 脚本需要其自身提供 map。
- 只限制 map 的访问 IP 可以吗?可以作为补充,但最简单可靠的做法是不部署。