download属性仅在同源url、服务端未强制inline、浏览器支持且文件可渲染时生效;ios safari完全不支持,跨域必须用fetch+blob方案。

download 属性本身不会“触发”下载,它只是告诉浏览器“这个链接的目标应该被保存为文件”,前提是满足同源、资源可获取、浏览器支持这三个硬条件。不满足任一条件,点击后依然会跳转或预览。
为什么加了 download 却还是打开 PDF/图片而不是下载
这是最常见误判:以为 download 是万能开关。实际它只在以下情况生效:
- href 指向的是同源 URL(比如
./report.pdf或/assets/logo.png),跨域链接(如https://cdn.example.com/file.pdf)直接忽略该属性 - 目标资源响应头未强制
Content-Disposition: inline—— 如果服务端返回了inline,浏览器优先听服务端的 - 浏览器支持该属性:iOS/iPadOS 全系 Safari 完全不认
download,点下去就是预览;部分旧版 Edge 也有兼容问题 - 文件类型本身可被浏览器原生渲染(PDF、PNG、JPEG、TXT 等),
download才有“覆盖权”;对不可渲染类型(如.zip、.exe)浏览器默认就下载,加不加都一样
动态创建 a 标签时,href 和 download 的设置顺序很重要
必须先赋值 href,再设 download,否则 Safari 和部分 Chrome 版本会静默失败(不报错,但点击无反应):
const a = document.createElement('a');
a.href = '/export/data.json'; // ✅ 必须先设 href
a.download = '用户数据-' + Date.now() + '.json'; // ✅ 再设 download
a.click();
如果反过来,或者用 setAttribute('download', ...) 后再设 href,某些浏览器会把 download 当作无效值丢弃。
跨域文件想下载,fetch + Blob 是唯一可控路径
当你要下载 CDN 上的图片、API 返回的 Excel 流、或后端动态生成的 HTML,download 属性完全失效,只能走 JS 构造:
- 确保接口允许 CORS(响应头含
Access-Control-Allow-Origin) - 用
fetch(url)获取响应体,调response.blob()而不是response.text()(二进制安全) -
URL.createObjectURL(blob)生成临时 blob URL,它天然同源,download可用 - 记得调
URL.revokeObjectURL(url)清理,否则内存泄漏
示例关键行:
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = '导出报表.xlsx'; // 这里命名才真正生效
a.click();
URL.revokeObjectURL(url); // ⚠️ 容易漏掉这句
download 属性值里的中文、空格、斜杠怎么处理
download 值不需要前端做 encodeURIComponent,现代浏览器(Chrome 85+、Firefox 79+、Edge 88+)原生支持 UTF-8 文件名。但要注意:
- 值里不能含
/、\、:、*、?、"、、<code>>、|—— 这些会被浏览器截断,最终保存为默认名(如download) - 值里带空格没问题(如
download="2024 年总结.pdf"),但 Windows 资源管理器可能显示异常,建议用短横线替代空格 - 服务器返回的
Content-Disposition头里若已指定filename*=UTF-8''...,浏览器会优先用那个,download值被忽略
真正难搞的不是命名,而是 Safari 全平台拒绝 download —— 如果你的用户大量使用 iOS,就得彻底放弃这个属性,统一走 fetch + Blob 方案,哪怕同源也得绕一圈。











