同源小文件直接用 ,api 返回流需 fetch + blob,大文件或需进度才用 readablestream;跨域、非 get、无用户手势触发时均失效,safari 有额外限制。

用 @#@#@#@#@#@#@#@#@#@0 就能触发浏览器自动下载,不跳转、不打开预览。
常见错误是把 download 用在跨域链接上——比如 href="https://example.com/file.zip",这时 download 属性会被浏览器忽略,点击后仍会跳转或在线打开。
-
download的值是可选的,不写就用原始文件名;写了就作为保存时的默认文件名(用户仍可修改) - 只支持
GET请求资源,不能用于POST或带身份验证的接口返回流 - Chrome、Edge、Firefox 支持良好;Safari 仅支持同源且必须是用户手势触发(比如真实 click,不能靠
click()模拟)
后端返回文件流时,前端必须用 fetch + Blob 处理
当文件来自 API 接口(如 /api/export?format=csv),且响应是 Content-Disposition: attachment 或纯二进制流时,<a download></a> 无效——因为浏览器无法直接解析响应头或内容。
必须用 fetch 获取响应,转成 Blob,再用 URL.createObjectURL() 创建临时地址供 <a></a> 下载:
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
fetch('/api/export?format=csv')
.then(res => res.blob())
.then(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'data.csv';
a.click();
URL.revokeObjectURL(url); // 用完立刻释放
});
- 漏掉
URL.revokeObjectURL(url)会导致内存泄漏,尤其频繁下载时明显 - 如果后端返回的是 JSON 错误(比如 401 或 500),
res.blob()仍会成功执行,但后续new Blob()内容是错误页 HTML——需先检查res.ok - 某些老版本 Android WebView 不支持
createObjectURL,得降级为location.href = 'data:...' + base64(仅适合小文件)
避免“点击无反应”:确保是用户主动触发
Chrome 和 Safari 对自动下载限制严格——如果不是由用户真实的鼠标 click、键盘 Enter 或空格触发,click() 调用会被静默拦截。
- 禁止在
setTimeout、fetch.then或load事件里直接调用a.click() - 正确做法:把下载逻辑封装成函数,在按钮的
onclick或addEventListener('click', ...)里调用 - React/Vue 等框架中,确保绑定事件的是原生 DOM 元素,而非被封装过的组件(否则可能丢失事件上下文)
大文件或需要进度提示?得用 ReadableStream 分块读取
直接 res.blob() 会把整个文件加载进内存,下载 100MB+ 文件容易卡死或 OOM。此时需用 response.body.getReader() 流式处理:
const reader = response.body.getReader();
const chunks = [];
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
}
const blob = new Blob(chunks, { type: response.headers.get('content-type') });
// 后续同 Blob 方案...
- 不是所有浏览器都支持
ReadableStream(IE 完全不支持,旧版 Safari 需要 polyfill) - 服务端必须开启 CORS 并暴露
Content-Length或使用分块传输(Transfer-Encoding: chunked) - 进度计算依赖
chunks累计长度,但无法精确知道总大小——除非响应头有Content-Length
同源小文件用 <a download></a>,API 返回流用 fetch + Blob,大文件或需进度才上流式读取——别一上来就堆复杂方案。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










