您现在的位置: 365建站网 > 365文章 > js 代码下载文件怎么写?createObjectURL 必须 revoke,跨域时 download 失效

js 代码下载文件怎么写?createObjectURL 必须 revoke,跨域时 download 失效

文章来源:365jz.com 点击数:10 更新时间:2024-08-18 08:35

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

js代码下载

一、内存数据怎么变成可下载的文件

流程固定三步: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建站器 »