经由过程 JavaScript 下载文件到当地(单文件)

近来在做一个
文件下载的功用,这里把做的历程顶用的手艺和坑扼要总结下。

1. 单文件下载(a标签)

同源单文件

针对单文件的情况下,同源的文件,能够经由过程 < a> 标签的 download 属性下载文件

  const elt = document.createElement('a');
  elt.setAttribute('href', url);
  elt.setAttribute('download', 'file.png');
  elt.style.display = 'none';
  document.body.appendChild(elt);
  elt.click();
  document.body.removeChild(elt);

然则这个计划并不适用于非同源的资本,此时它相当于平常的超链接,点击会跳转到资本页面,而不是下载。

非同源图片

假如不存在CORS题目, 能够借助Blob完成下载(组织xhr请求文件地点, 以Blob的情势吸收Response):

function downloadWithBlob(url) {
  fetch(url).then(res => res.blob().then(blob => {
    var a = document.createElement('a');
    var url = window.URL.createObjectURL(blob);
    var filename = 'file.png';
    a.href = url;
    a.download = filename;
    a.click();
    window.URL.revokeObjectURL(url);
  }));
}

假如存在CORS题目,能够斟酌运用 canvas 将图片转换成 base64 编码以后再经由过程 标签的 download 属性下载

function downloadPic(url) {
  const img = new Image;
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  img.onload = function() {
    canvas.width = this.width;
    canvas.height = this.height;
    ctx.drawImage(this, 0, 0);

    const elt = document.createElement('a');
    elt.setAttribute('href', canvas.toDataURL('image/png'));
    elt.setAttribute('download', 'file.png');
    elt.style.display = 'none';
    document.body.appendChild(elt);
    elt.click();
    document.body.removeChild(elt);
  };
  img.crossOrigin = 'anonymous';
  img.src = url;
}

2. 单文件下载(iframe)

iframe体式格局是在页面内隐蔽iframe, 然后将下载地点加载到iframe中, 从而触发浏览器的下载行动

  const iframe = document.createElement('iframe');
  iframe.src = url;
  iframe.style.display = 'none';
  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)

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

后端

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

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

    原文作者:小闲
    原文地址: https://segmentfault.com/a/1190000018505050
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞