download属性仅对同源url生效,跨域、file://协议、safari及非法文件名均导致失效;可靠方案是fetch+blob生成同源url下载,大文件应交由服务端处理。

download 属性只对同源 URL 生效
它根本不会生效,不是 bug,是浏览器强制执行的同源策略。只要 href 指向跨域地址(不同域名、协议如 http vs https、或端口),download 就被静默丢弃——点击后跳转或预览,控制台也不报错。
常见失效场景包括:
- CDN 上的 PDF:
href="https://cdn.example.com/report.pdf" - 本地双击打开 HTML 文件(
file://协议下所有download都无效) - 后端 API 接口:
href="/api/export?format=xlsx"(若页面在https://app.com,而接口走代理但实际响应头未带Access-Control-Allow-Origin,仍算跨域)
文件名赋值含非法字符或路径会被忽略
download 值不是路径,只是建议文件名;浏览器会剥离 /、\、: 等非法字符,空值或纯路径写法会导致整个属性退化为无效。
合法写法示例:
-
download="invoice-202408.pdf"(显式带后缀,Firefox 必须这样) -
download="用户导出数据.xlsx"(UTF-8 中文名现代浏览器支持)
非法写法示例:
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
-
download="./export/data.json"→ 静默失效 -
download="report:final.txt"→ 冒号被过滤,可能存成reportfinal.txt或退化为原始名 -
download=""或download=" "→ 直接忽略
服务端响应头优先级高于 download 属性
真正决定最终文件名的是 HTTP 响应头:Content-Disposition: attachment; filename="real-name.pdf"。只要服务端返回了这个头,无论你写 download="test.csv",用户看到的都是 real-name.pdf。
这意味着:
- 前端
download是“建议”,不是“指令” - 如果后端返回
Content-Type: application/json但没设Content-Disposition,浏览器可能直接渲染 JSON,不触发下载 - 某些资源类型(如
text/html、image/png)即使同源,也可能被预览而非下载——必须靠服务端明确声明attachment
移动端 Safari 和大文件场景必须换方案
iOS/iPadOS 全系 Safari 完全不支持 download 属性,哪怕同源也打开预览页。唯一可靠路径是:用 fetch 获取二进制流 → 转 Blob → URL.createObjectURL() → 绑定 download。
但要注意:
- 大文件(>100MB)会吃内存,可能卡顿或触发警告
-
URL.createObjectURL()创建的 URL 必须手动URL.revokeObjectURL()清理,否则内存泄漏 - Safari 15.4+ 才稳定支持
createObjectURLfor Blob,旧版需降级 fallback
真正可控的重命名,从来不在 a 标签上硬写 download,而在数据落地前完成封装——这是绕过服务端限制和浏览器策略的唯一通用解法。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










