一行代码解决 Chrome 对 HTTP 站点 Office 文件的下载拦截
Chrome 拦截 HTTP 站点的文件下载?一行代码改掉它的判断逻辑
问题:用户点导出,Chrome 弹"不安全"
一个内网系统通过 HTTP 提供服务,导出功能生成 .docx 文件。Chrome 每次下载都弹:
此文件可能不安全/可能已被篡改
非技术用户不敢点"保留",以为系统坏了。
排查:代码明明已经用 Blob 下载了
前端代码是这样写的:
// API 层:用 responseType: 'blob' 获取二进制
const response = await request.download({ url: '/api/report/export' })
// 前端层:提取文件名,用 Blob URL 触发下载
download.word(response.data, fileName)
download.word() 内部走的就是 URL.createObjectURL(blob) + <a download> 点击。早就不是浏览器原生下载了——为什么还拦?
后来发现,Chrome 的判断不看下载方式,看服务器说了什么。
根因:一个 HTTP 头引发的拦截
后端 Controller 是这样写响应头的:
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
response.setHeader("Content-Disposition", "attachment; filename=\"工作周报.docx\"");
Chrome 的处理链:
响应头含 Content-Disposition: attachment
→ Chrome 判定:"这是个要下载的文件"
→ 检查:来源是 HTTP?
→ 检查:文件类型在危险名单里?(docx ✅、zip ✅、exe ✅)
→ 弹警告
Content-Disposition: attachment 就是触发 Chrome 下载安全检查的开关。 你关掉它,Chrome 就不再走那条检查链路。
我们试过的三个方案
方案 A:搭 HTTPS(失败)
- 给测试服务器绑了 mkcert 自签证书
- 每个开发者/用户都要手动装根证书
- 非技术用户:"什么叫证书?怎么装?"
- 放弃
方案 B:data: URI 下载(未遂)
想把 Blob 读成 base64,用 data:application/vnd... 格式触发下载,绕过 HTTP 来源追踪。
但 data: URI 对大文件不友好(base64 编码膨胀 33%),且逻辑上还是在绕安全机制,不够干净。
方案 C:让服务器闭嘴(成功)
核心思路:既然 Content-Disposition: attachment 是你拦截的判断依据,那我就不发这个头。
文件内容照样传、文件名照样给、下载照样触——只是"这是下载文件"这句话不让服务器说,改由 JS 说。
最终方案:一行改动的全部代码
后端
// 改前
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// 改后——去掉 Content-Disposition: attachment
response.setHeader("X-Filename", URLEncoder.encode(fileName, StandardCharsets.UTF_8));
前端
// 改前
const disposition = response?.headers?.['content-disposition'] || ''
const match = /filename\*=UTF-8''([^;]+)/i.exec(disposition)
fileName = match ? decodeURIComponent(match[1]) : fallback
// 改后——优先读 X-Filename,兼容旧版 Content-Disposition
const xFilename = response?.headers?.['x-filename'] || ''
if (xFilename) {
fileName = decodeURIComponent(xFilename)
} else {
// 兼容旧版
const match = /filename\*=UTF-8''([^;]+)/i.exec(response?.headers?.['content-disposition'] || '')
if (match) fileName = decodeURIComponent(match[1])
}
改完部署,用户点导出——不弹警告了。
为什么这样能绕过 Chrome?
改前流程:
服务器 → 浏览器:"接住,这是个要下载的 .docx 文件"
浏览器 → "HTTP 来的 .docx?不安全!" → 弹警告
改后流程:
服务器 → 浏览器:"这是数据流"(没有 attachment 头)
JS → 浏览器:"帮我把这段数据保存为文件"(Blob URL + <a download>)
浏览器 → "JS 让我存数据,不管来源" → 正常下载
Chrome 不会对 JS 发起的 Blob URL 下载做安全检查——那是用户代码的行为,不是网络层的文件传输。
意外发现:为什么 Excel 不弹警告?
测试过程中发现,同系统的 Excel 导出从不触发警告。看了代码,Excel 和 Word 用的是完全相同的下载链路(responseType: 'blob' + URL.createObjectURL)。
最后查 Chrome 源码确认:Chrome 对 .docx 和 .xlsx 的安全策略不同。 .docx 历史上是宏病毒的常见载体,被列为"高风险"类型;.xlsx 虽然也在危险名单里,但 Chrome 的拦截阈值对 Word 文档更严格。
如果你的系统同时有 Excel 和 Word 导出,别奇怪——不是你代码的问题,是 Chrome 的区别对待。
一句话总结
不要让服务器对 Chrome 说"这是下载文件"(
Content-Disposition: attachment)。让 JS 自己下载。Chrome 不拦自己人。
适用场景
- 内网 HTTP 站点导出 Office 文档(
.docx、.xlsx、.pptx) - 导出 ZIP 压缩包
- 任何 Chrome 标记为"不安全下载"的 HTTP 文件传输
局限性
这个方案的本质是绕过 Chrome 的检查,不是修复 HTTP 的安全问题。如果你的系统面向公网或有合规要求,长期方案仍然是上 HTTPS + 域名 + 公网 CA 证书。

浙公网安备 33010602011771号