资讯专栏INFORMATION COLUMN

通过 JavaScript 下载文件到本地(单文件)

Julylovin / 866人阅读

摘要:最近在做一个文件下载的功能,这里把做的过程中用的技术和坑简要总结下。前端假设代理服务接口是后端单文件的处理先写到这里,多文件的下载下篇在写。

</>复制代码

  1. 最近在做一个文件下载的功能,这里把做的过程中用的技术和坑简要总结下。
1. 单文件下载(a标签) 同源单文件

针对单文件的情况下,同源的文件,可以通过 < a> 标签的 download 属性下载文件

</>复制代码

  1. const elt = document.createElement("a");
  2. elt.setAttribute("href", url);
  3. elt.setAttribute("download", "file.png");
  4. elt.style.display = "none";
  5. document.body.appendChild(elt);
  6. elt.click();
  7. document.body.removeChild(elt);

但是这个方案并不适用于非同源的资源,此时它相当于普通的超链接,点击会跳转到资源页面,而不是下载。

非同源图片

如果不存在CORS问题, 可以借助Blob实现下载(构造xhr请求文件地址, 以Blob的形式接收Response):

</>复制代码

  1. function downloadWithBlob(url) {
  2. fetch(url).then(res => res.blob().then(blob => {
  3. var a = document.createElement("a");
  4. var url = window.URL.createObjectURL(blob);
  5. var filename = "file.png";
  6. a.href = url;
  7. a.download = filename;
  8. a.click();
  9. window.URL.revokeObjectURL(url);
  10. }));
  11. }

如果存在CORS问题,可以考虑使用 canvas 将图片转换成 base64 编码之后再通过 标签的 download 属性下载

</>复制代码

  1. function downloadPic(url) {
  2. const img = new Image;
  3. const canvas = document.createElement("canvas");
  4. const ctx = canvas.getContext("2d");
  5. img.onload = function() {
  6. canvas.width = this.width;
  7. canvas.height = this.height;
  8. ctx.drawImage(this, 0, 0);
  9. const elt = document.createElement("a");
  10. elt.setAttribute("href", canvas.toDataURL("image/png"));
  11. elt.setAttribute("download", "file.png");
  12. elt.style.display = "none";
  13. document.body.appendChild(elt);
  14. elt.click();
  15. document.body.removeChild(elt);
  16. };
  17. img.crossOrigin = "anonymous";
  18. img.src = url;
  19. }
2. 单文件下载(iframe)

iframe方式是在页面内隐藏iframe, 然后将下载地址加载到iframe中, 从而触发浏览器的下载行为

</>复制代码

  1. const iframe = document.createElement("iframe");
  2. iframe.src = url;
  3. iframe.style.display = "none";
  4. document.body.appendChild(iframe);

但是这里发现,即使是同域的图片,也无法完成下载,这是为啥呢?

这里就有个上面的a链接下载没有提到的问题:什么样的链接才能触发浏览器的下载:

url如何触发浏览器自动下载

一个url能否触发浏览器自动下载,主要看该请求响应头response header是否满足,一般是看Content-DispositionContent-Type这两个消息头:

response header中指定了Content-Disposition为attachment,它表示让浏览器把消息体以附件的形式下载并保存到本地 (一般还会指定filename, 下载的文件名默认就是filename)

response header中指定了Content-Type 为 application/octet-stream(无类型) 或 application/zip(zip包时)等等。(其中 application/octet-stream表示http response为二进制流(没指定明确的type), 用在未知的应用程序文件,浏览器一般不会自动执行或询问执行。浏览器会像对待 设置了HTTP头Content-Disposition 值为 attachment 的文件一样来对待这类文件)

只要url满足上述触发的要求,那么都可以通过iframe的形式来下载

3. 代理服务处理下载

如果后端自己也能控制的话,或者后端能配合的话,可以写一个代理服务,在后端去请求文件数据,然后设置好相应的response header, 然后前端请求代理服务来做下载。

前端(假设代理服务接口是http://exampale.com/download):

</>复制代码

  1. const downloadUrl = "http://exampale.com/download?url=" + encodeURIComponent(url) + "&name=xxx";
  2. const elt = document.createElement("a");
  3. elt.setAttribute("href", downloadUrl);
  4. elt.setAttribute("download", "file.png");
  5. ...

后端

</>复制代码

  1. const url = decodeURIComponent(req.query.url);
  2. http.get(url, (response) => {
  3. res.setHeader("Content-disposition", "attachment;filename=" + req.query.name);
  4. res.setHeader("Content-type", "application/octet-stream");
  5. response.pipe(res);
  6. });

单文件的处理先写到这里,多文件的下载下篇在写。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/102517.html

相关文章

  • 通过 Node 批量下载文件本地(多文件

    摘要:包批量下载虽然说可以遍历所有文件,然后去批量下载单个文件,但是这种体验毕竟不太好,最常见的做法是把批量的文件下载并打包到中。 最近在做一个文件下载的功能,这里把做的过程中用的技术和坑简要总结下。上篇文章《通过 JavaScript 下载文件到本地(单文件)》说了下如何下载单文件,这篇主要说下如何做多文件的批量下载 多文件分别处理 如果文件数量可控,对于下载出来的文件格式无要求,可以用最...

    plus2047 评论0 收藏0
  • nodejs 基础篇整合

    摘要:基础篇整合最近有朋友也想学习相关方面的知识,如果你是后端想接近前端,作为一门跑在服务端的语言从这里入门再好不过了。事件驱动机制是通过内部单线程高效率地维护事件循环队列来实现的,没有多线程的资源占用和上下文的切换。 nodeJs 基础篇整合 最近有朋友也想学习nodeJs相关方面的知识,如果你是后端想接近前端,node作为一门跑在服务端的JS语言从这里入门再好不过了。如果你正好喜欢前端,...

    lemanli 评论0 收藏0
  • nodejs 基础篇整合

    摘要:基础篇整合最近有朋友也想学习相关方面的知识,如果你是后端想接近前端,作为一门跑在服务端的语言从这里入门再好不过了。事件驱动机制是通过内部单线程高效率地维护事件循环队列来实现的,没有多线程的资源占用和上下文的切换。 nodeJs 基础篇整合 最近有朋友也想学习nodeJs相关方面的知识,如果你是后端想接近前端,node作为一门跑在服务端的JS语言从这里入门再好不过了。如果你正好喜欢前端,...

    lentrue 评论0 收藏0
  • nodejs 基础篇整合

    摘要:基础篇整合最近有朋友也想学习相关方面的知识,如果你是后端想接近前端,作为一门跑在服务端的语言从这里入门再好不过了。事件驱动机制是通过内部单线程高效率地维护事件循环队列来实现的,没有多线程的资源占用和上下文的切换。 nodeJs 基础篇整合 最近有朋友也想学习nodeJs相关方面的知识,如果你是后端想接近前端,node作为一门跑在服务端的JS语言从这里入门再好不过了。如果你正好喜欢前端,...

    高胜山 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<