download属性不是下载开关,而是同源提示信号;仅在同源静态路径、blob url或短data url三种场景下生效,跨域、file://协议、safari及content-disposition:inline均使其失效。

download 属性根本不是下载开关,而是同源提示信号
加了 download 却没反应?不是你代码写错了,是浏览器压根没让它生效。它只在三种情况下起作用:同源静态路径(href="/files/report.pdf")、blob: URL、短 data: URL。跨域链接(哪怕只是 CDN 域名和主站不同)会被静默忽略——控制台可能连警告都不报,Network 面板里能看到请求发出去了,但页面跳转或直接预览,就是被拦截的实锤。
常见误判包括:
- 以为
download="xxx.xlsx"能强制下载远程文件,实际只是建议保存名,且仅对本地可访问资源有效 - 在
file://协议下测试,所有download全部失效,必须起本地服务(如npx serve) - 用 Safari 点击同源链接,依然打开预览——Safari 全系不支持
download属性 -
download值含非法字符(如/、:、\),整个属性被丢弃,浏览器当它不存在
真正可控的下载路径只有 fetch + Blob
要下载跨域资源或 API 返回的二进制流,必须绕过 a[download] 的同源限制。核心是把响应体转成可信的 blob: URL:
-
fetch必须显式声明{ mode: 'cors' },否则即使服务端开了 CORS,也可能因默认no-cors模式导致响应不可读 - 务必调用
response.blob(),不是response.text()——后者会破坏 PDF/Excel/ZIP 的二进制结构 - 从
Content-Disposition头提取文件名,需服务端开启Access-Control-Expose-Headers: Content-Disposition - 每次下载后必须调用
URL.revokeObjectURL(),否则 blob URL 持久驻留内存,大文件多次操作易触发 OOM
服务端 Content-Disposition 才是全链路兼容的下载指令
前端 download 是“建议”,服务端 Content-Disposition: attachment; filename="export.csv" 才是真正起效的强制下载开关。它不依赖同源,不关心你用不用 a 标签,甚至直接访问 URL 也会触发下载对话框。
容易被忽略的关键点:
- Nginx/Apache 没配
add_header Content-Disposition "attachment; filename=$1";,前端写再漂亮的 HTML 也没用 - 服务端返回了
Content-Disposition: inline,会覆盖任何前端download行为 - 如果服务端
Content-Type是text/html或浏览器能直接渲染的类型,部分浏览器(尤其 Safari)仍可能忽略download
代码质量防护:别让 download 成为安全盲区
很多人把 download 当作功能开关,却没意识到它暴露的是服务端配置漏洞。一个没设 Content-Disposition 的文件接口,可能被恶意构造链接诱导用户下载伪造内容;而盲目信任前端 download 值,还可能被注入路径遍历(虽然浏览器会忽略斜杠,但服务端若未校验原始 URL,风险仍在)。
真正需要检查的不是 HTML 写法,而是:
- 服务端是否对所有文件下载接口统一设置
Content-Disposition: attachment - 是否限制
Access-Control-Allow-Origin的宽泛值(如*)用于敏感文件接口 - 是否对
Content-Type做白名单校验(避免返回text/html导致 XSS) - 代理转发逻辑中是否透传了原始
Content-Disposition和Content-Type
最常出问题的地方不在前端代码行数,而在 Nginx 配置漏了一行 header,或后端框架默认没开 expose headers。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











