js 代码下载文件怎么写?createObjectURL 必须 revoke,跨域时 download 失效
用 JS 触发下载有两类需求:把内存里生成的数据(表格导出、JSON 报表)存成文件,以及给已有链接强制指定文件名。前者靠对象 URL,后者用 download 属性,两条路都有坑:内存泄漏与跨域失效。本文依据 MDN 的 createObjectURL() 与 <a> 元素页(实测均 200)原文整理。

一、内存数据怎么变成可下载的文件
流程固定三步:Blob 打包数据 → URL.createObjectURL() 拿到临时地址 → 挂到 <a> 上模拟点击 → revokeObjectURL() 释放。MDN 对 createObjectURL 的定义原文是:"The createObjectURL() static method of the URL interface creates a string containing a blob URL pointing to the object given in the parameter",并紧接着给出释放方式:"To release an object URL, call revokeObjectURL()."
参数要求为 "A Blob (such as a File) or MediaSource object",返回 "A string containing an object URL"。典型写法:
function saveText(text, name) { const blob = new Blob([text], { type: "text/plain;charset=utf-8" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = name; a.click(); URL.revokeObjectURL(url);}
二、不 revoke 就是内存泄漏
对象 URL 会持有 Blob 引用,不撤销就要等页面卸载才回收,反复导出时内存持续上涨。MDN 有一句分量很重的说明:"This feature is not available in Service Workers due to its potential to create memory leaks."——官方在 Service Worker 环境直接禁用该能力,理由正是内存泄漏,可见 revoke 不是可选动作。
也不要用 data: URL 承载大文件:整份数据被编进字符串,内存与解析开销更大,超长时各家行为还不一致。
三、download 属性:文件名从哪来
MDN 对 download 的定义原文是:"Causes the browser to treat the linked URL as a download. Can be used with or without a filename value"。不写值时由浏览器推断,官方列出推断来源:"The Content-Disposition HTTP header、The final segment in the URL path、The media type(from the Content-Type header, the start of a data: URL, or Blob.type for a blob: URL)"。
写值时也有明确规则:"defining a value suggests it as the filename. / and \ characters are converted to underscores (_). Filesystems may forbid other characters in filenames, so browsers will adjust the suggested name if necessary." 也就是说属性里只能"建议"文件名,浏览器有权按文件系统限制改名,不能把它当作强约束。若同时存在 Content-Disposition 响应头,服务端意图会覆盖前端建议。
四、跨域时 download 会被忽略
这是线上最常出现"文件名没生效/直接打开了页面"的原因:download 属性只对同源 URL 或 blob:/data: URL 有效,指向跨域地址时浏览器忽略该属性、按普通导航处理。所以想给 CDN 上的图片强制改名下载,纯前端做不到,必须由服务端补 Content-Disposition: attachment; filename=,或者把资源经同源接口转发。
同理,window.open(url) 或把对象 URL 放进 <a target="_blank"> 都只是打开预览,不等于下载。
五、导出表格与 CSV 的两个隐患
用 join(",") 拼 CSV 极易出错:单元格含逗号、换行、双引号就会错位,须给每个字段加引号并把内部引号翻倍。中文 CSV 还要带 UTF-8 BOM,否则 Excel 打开乱码,做法是把 "\uFEFF" 放在开头。若数据来自接口,直接让响应给出 Content-Disposition 更省事,不必在浏览器内拼装。
六、常见问题 FAQ
问:点击下载没反应?
答:多为同一事件内连续 click 多个链接被浏览器拦截,或链接元素已被移出 DOM。
问:文件名里的中文变下划线?
答:属正常,官方说明浏览器会按文件系统限制调整建议名。
问:能否用 JS 直接写入用户指定路径?
答:不能,出于安全网页无写盘能力,只能触发下载。要读写本地文件用 File System Access API 并由用户授权。
七、总结
用 JS 触发下载的可靠做法是:①内存数据一律 Blob + createObjectURL + revokeObjectURL 三步闭环,官方明确该特性在 Service Worker 中被禁用、理由是内存泄漏风险;②文件名靠 download 属性只能是"建议",官方写明 / 与 \ 会被转成下划线且浏览器可再调整,存在 Content-Disposition 时以服务端为准;③download 对跨域 URL 无效,必须服务端加响应头或同源转发;④大文件别用 data: URL,CSV 记得加 BOM 并对字段做引号转义。遇到"没下载/名字不对",第一嫌疑是跨域,第二是没 revoke 导致的内存或句柄问题。
生产内容,同时打通搜索引擎(SEO)与AI搜索引擎(GEO)流量入口的软件! 点击进入365建站器 »
