0


前端文件下载方法总结

前端文件下载方法总结

1、open或location.href

最简单最直接的方式,跟a标签访问下载链接一样
前提:下载地址不需要鉴权 以及 不存在跨域问题

window.location.href = url // url为下载地址
window.open('downloadFile.zip');

优点:简单方便

缺点:

  • 直接访问可能会覆盖当前页面地址
  • 不能添加header,也就不能进行鉴权
  • 会出现URL长度限制问题
  • 需要注意url编码问题
  • 浏览器可直接浏览的文件类型是不提供下载的,如txt、png、jpg、gif、pdf等
  • 无法知道下载的进度

2、用a标签下载

a标签可以访问下载文件的地址。如果 是对于浏览器可以直接浏览的文件类型:jpg\png\gif\txt等,a标签不能直接下载。

所以,在html5中,a标签提供了

download

属性。

简单用法:

<a href="example.jpg" download>点击下载</a>//如果带属性值 指定下载的文件名,即重命名下载文件。不设置的话默认是文件原本名。<a href="example.jpg" download="test">点击下载</a>

动态a标签:
下面的

url

即文件或接口的地址
如需要额外参数,通过

url

后问号拼接参数,后端

get

请求方式接收

服务端需要配置

url

资源的响应头

Content-disposition

值为

attachment

,浏览器识别会调用下载弹窗,进一步配置

filename

值即下载的默认文件名。

// 封装functiondownloadFile(url, name){
  url = url ||''
  name = name ||''let ele = document.createElement('a')
  ele.target ='_blank'
  ele.href = url
  ele.download = name
  ele.click()
  ele =null}// 调用downloadFile(url)

判断浏览器是否支持

download

属性:

const isSupport ='download'in document.createElement('a');

需要注意一些信息:

  • Edge 13在尝试下载data url链接时会崩溃。
  • Chrome 65及以上版本只支持同源下载链接。
  • Firefox只支持同源下载链接。

基于上面描述,如果你尝试下载跨域链接,那么其实download的效果就会没了,跟不设置download表现一致。即浏览器能预览的还是会预览,而不是下载。

对于在跨域下不能下载可浏览的文件,得跟后端协商,在后端层做多一层转发,最终返回给前端的文件链接跟下载页同域。

优点:

download

属性能解决不能直接下载浏览器可浏览的文件

缺点:

  • 不能下载跨域下的浏览器可浏览的文件
  • 不能进行鉴权
  • url资源或接口响应头配置了filename时,前端无法自定义下载文件名。
  • 有兼容性问题,特别是IE
  • 前端需要自定义展示下载进度条需求时无法支持。

3、利用Blob下载,发送ajax请求api获取文件流进行下载

这种方法除了能利用已知文件地址路径进行下载外,还适用于需要调取API获取文件流下载的形式。
有些时候后端不会直接提供一个下载地址给你直接访问,而是要调api。

方法:

前端请求接口设置

responseType: 'blob'

, 统一 转为Blob 数据,然后利用URL.createObjectUrl生成url地址,赋值在a标签的href属性上,结合download进行下载.

blob 是 js 里表示二进制文件的对象。

target.response就是一个Blob对象,打印出来会看到两个属性size和type。

2种方法代码参考

文件下载方法参考,第二种可设置下载进度。
参考:https://blog.csdn.net/u010059669/article/details/122623034

/**
 * 第一种方法:
 * @param {String} path - 下载地址/下载请求地址。
 * @param {String} name - 下载文件的名字/重命名(考虑到兼容性问题,最好加上后缀名)
 */downloadFile(path, name){const xhr =newXMLHttpRequest();
    xhr.open('get', path);
    xhr.responseType ='blob';
    xhr.send();
    xhr.onload=function(){if(this.status ===200||this.status ===304){// 如果是IE10及以上,不支持download属性,采用msSaveOrOpenBlob方法,但是IE10以下也不支持msSaveOrOpenBlobif('msSaveOrOpenBlob'in navigator){
                navigator.msSaveOrOpenBlob(this.response, name);return;}// const blob = new Blob([this.response], { type: xhr.getResponseHeader('Content-Type') });// const url = URL.createObjectURL(blob);const url =URL.createObjectURL(this.response);const a = document.createElement('a');
            a.style.display ='none';
            a.href = url;
            a.download = name;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);URL.revokeObjectURL(url);}};}/**
 * 第二种方法:
 * @description: ajax下载/导出文件
 * @param {string} url 资源或接口地址,可携带参数
 * @param {function} progressCallback 选填,前端自定义的下载进度回调
 */functiondownloadFromApi(url, progressCallback){returnnewPromise((resolve, reject)=>{const xhr =newXMLHttpRequest()
    xhr.open('get', url)
    xhr.responseType ='blob'
    xhr.onload=e=>{if(xhr.status ===200){const response = xhr.response
        resolve(response)const dispoition = xhr.getResponseHeader('Content-Disposition')||''const nameStr = dispoition.split(';')[1]||''const fileName =decodeURIComponent(nameStr.split('=')[1]||'')if(window.navigator.msSaveOrOpenBlob){// 兼容处理,ie下的blob下载
          window.navigator.msSaveOrOpenBlob(response, fileName)}else{const href =URL.createObjectURL(response)let ele = document.createElement('a')
          ele.target ='_blank'
          ele.href = href
          ele.download = fileName
          ele.click()
          ele =nullURL.revokeObjectURL(href)}}else{reject(newError(`${xhr.status}:请求失败`))}}
    xhr.error=err=>{reject(err)}
    xhr.onprogress=e=>{if(e.lengthComputable){const percentComplete = e.loaded / e.total
        progressCallback &&progressCallback(percentComplete)}}
    xhr.send(null)})}

下载进度设置的原理

服务端需要配置响应头的Content-Length,值为文件大小(未配置的话会在文件传输完成后才弹窗提示下载,响应感知太慢)。

前端监听xhr对象的progress事件:

xhr.onprogress=e=>{if(e.lengthComputable){const percentComplete = e.loaded / e.total
    // 打印当前已完成的进度比例
    console.log(percentComplete)}}

另一种封装方式(axios 请求)

如果是封装了axios请求,可以在调请求后,使用下面的封装的downLoadFile 方法,使用示例:

/*
httpRequest: 封装的下载API请求,记得设置responseType = 'blob'
url: 接口
*/httpRequest(url).then(async(res)=>{
   console.log('下载请求返回:', res);const{ data, response }= res;if(data && response.status ===200){// 调用封装好的下载文件的方法downLoadFile(data, response);}}).catch(async(err)=>{
   console.log(err);});/**
 * 下载文件
 * @param {any} data - 下载请求返回blob对象的data, 打印出来会有一个size和type 属性。
 * @param {Response} response- 请求的response
 */constdownLoadFile=(data: any,response: Response)=>{let contentType = response.headers.get('content-type')||undefined;let contentDisposition = response.headers.get('content-disposition')||undefined;

  contentType =isExistValue(contentType)? contentType :undefined;
  contentDisposition =isExistValue(contentDisposition)? contentDisposition :undefined;// 文件名提取let filename ='xxx';if(typeof contentDisposition ==='string'){
    contentDisposition =valueToLowerCase(contentDisposition);try{// 文件名提取
      filename = contentDisposition.match(/filename=(.*)/)[1];}catch(err){
      console.log(err);// @ts-ignore
      filename = contentDisposition;}}// 创建一个 Blob 对象const blob =newBlob([data],{type: contentType });// @ts-ignoreif(typeof window.navigator.msSaveBlob !=='undefined'){// 兼容IE,window.navigator.msSaveBlob:以本地方式保存文件
    window.navigator.msSaveBlob(blob,decodeURI(filename));}else{const href = window.URL.createObjectURL(blob);const eLink = document.createElement('a');// 创建一个<a>标签
    eLink.style.display ='none';// 隐藏标签
    eLink.href = href;// 配置href,指向本地文件的内存地址
    eLink.download =decodeURI(filename);
    document.body.appendChild(eLink);
    eLink.click();// 释放URL 对象
    document.body.removeChild(eLink);// 释放掉blob对象URL.revokeObjectURL(href);}};

图片预览

如果是图片预览,也是后端返回的地址,需要带上token去请求。需要用到base64。伪代码参考思路:

const[imgSrc, setImgSrc]=useState('');// 图片预览的srcuseEffect(()=>{const url ='xxx.xx.xx/img/wx.png';// httpRequest自己封装的axios请求 , responseType 为 'blob'httpRequest(url).then(async(res)=>{
    console.log('下载返回:', res);const{ data, response }= res;if(data && response.status ===200){// 生成图片预览的srcconst src =awaitblobToBase64(data);setImgSrc(src);}});},[]);/**
 * Blob 图像对象预览
 * */constblobToBase64=(file: Blob)=>{returnnewPromise((resolve, reject)=>{const reader =newFileReader();
    reader.readAsDataURL(file);
    reader.onload=()=>resolve(reader.result);
    reader.onerror=(error)=>reject(error);});};// 在Image标签中使用:<Image width="80%" alt={name} src={imgSrc}/>

优点:

  • 能解决不能直接下载浏览器可浏览的文件
  • 可添加鉴权信息

缺点: 兼容性问题,IE10以下不可用

标签: 前端

本文转载自: https://blog.csdn.net/yqdid/article/details/134293103
版权归原作者 yqdidy 所有, 如有侵权,请联系我们删除。

“前端文件下载方法总结”的评论:

还没有评论