download 属性仅是同源下的文件名建议和下载意图提示,是否真正下载取决于 href 是否同源、服务端是否返回 content-disposition: attachment 及文件类型是否被浏览器预览。

download 属性为什么点了还是打开 PDF 而不是下载
它根本不是“触发下载”的开关,只是个同源场景下的文件名建议 + 下载意图提示。浏览器是否真下载,取决于三件事:href 是否同源、服务端是否返回 Content-Disposition: inline、文件类型是否被浏览器默认预览(如 application/pdf、image/png)。加了 download 但点开仍是 PDF 预览,大概率是服务端没设 Content-Disposition: attachment,或者 href 指向了跨域地址(比如 CDN 上的 https://cdn.example.com/report.pdf)——此时该属性直接被忽略。
同源静态文件怎么用 download 安全生效
必须同时满足:协议 + 域名 + 端口完全一致,且服务端不返回 Content-Disposition: inline。常见可落地写法:
-
@#@#@#@#@#@#@#@#@#@0—— ✅ 推荐,路径相对、同源、扩展名明确 -
@#@#@#@#@#@#@#@#@#@1—— ✅download值为空时,浏览器会从 URL 路径提取文件名(report.pdf) -
@#@#@#@#@#@#@#@#@#@2—— ✅data:URL 天然同源,download生效 - 避免写成
href="https://your-domain.com:8080/file.json"—— ❌ 端口不同即算跨源,download失效
跨域或 API 返回文件流时必须走 fetch + Blob
当 href 是 https://api.example.com/export?format=csv 或 https://oss.aliyuncs.com/file.zip,download 属性完全无效,唯一可控路径是 JS 构造本地 blob URL:
- 服务端接口必须返回
Access-Control-Allow-Origin(允许当前域名),否则fetch直接被 CORS 拦截 - 一定要用
response.blob(),不用response.text()—— 否则二进制文件(如 Excel、PDF)会损坏 -
a.href必须先赋值,再设a.download;顺序反了在 Safari 和部分 Chrome 版本中静默失败 - 必须调用
URL.revokeObjectURL(url),否则每次下载都复制一份数据到内存,大文件频繁下载会撑爆内存 - iOS Safari 全系不支持脚本触发下载,哪怕 blob URL 同源,点击后也只预览 —— 这点容易被忽略,需提前告知用户右键“保存到文件”
真正强制下载的控制权其实在服务端
前端 download 是弱提示,Content-Disposition: attachment 响应头才是硬指令。只要服务端返回这个头,无论是否同源、是否加 download、什么浏览器,都会弹下载框:
- Nginx 静态文件配置:
add_header Content-Disposition "attachment";(注意无法动态设 filename) - Express 中:
res.setHeader('Content-Disposition', 'attachment; filename="export-2026.csv"'); - PHP 中:
header('Content-Disposition: attachment; filename="data.json"'); - 如果服务端已返回
Content-Disposition: attachment; filename="server-name.pdf",前端a.download的值会被大多数浏览器忽略
最易被忽略的其实是服务端响应头和前端路径的配合关系:你以为加了 download 就万事大吉,其实浏览器早把决定权交给了后端那行 Content-Disposition。跨域、iOS、PDF 预览问题,归根结底都是在提醒你——别只盯着 HTML 标签,得看那一整条 HTTP 响应链。











