前端实现文件下载的方法

Posted MoXinXueWEB

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端实现文件下载的方法相关的知识,希望对你有一定的参考价值。

前端实现文件下载

前端下载一般分为两种情况,一种是后端直接给一个文件地址,通过浏览器打开就可以下载,另外一种则需要发送请求,后端返回二进制流数据,前端解析流数据,生成URL,实现下载。

一、location.href

对于一些浏览器无法识别的文件格式,可以直接再浏览器地址栏输入url即可触发浏览器的下载功能。对于单文件下载没有什么问题,但是如果下载多文件,点击过快就会重置掉前面的请求

适用场景:

  • get请求
  • 单文件下载
window.location.href = url;

二、window.open

和location.href类似

window.open(url);

三、a标签

直接下载仅适用于浏览器无法识别的文件。如果是浏览器支持的文件格式,如html、jpg、png、pdf等,则不会触发文件下载,而是直接被浏览器解析并展示,这种情况下,可以使用a标签下载文件,download属性可以设置文件名。适用于单文件下载,如果下载多文件,点击过快就会重置掉前面的请求。

适用场景:

  • get请求
  • 单文件下载
  • 需要自定义文件名
//写法1
const download = (filename, url) => 
    let a = document.createElement('a'); 
    a.style = 'display: none'; // 创建一个隐藏的a标签
    a.download = filename;
    a.href = url;
    document.body.appendChild(a);
    a.click(); // 触发a标签的click事件
    document.body.removeChild(a);

// 写法2
<a href="/images/download.jpg" download="myFileName">

注意:有时候对于浏览器可识别的文件格式,我们还是需要直接下载的情况,可以声明一下文件的header的 Content-Disposition信息,告诉浏览器,该链接为下载附件链接,并且可以声明文件名

Content-Disposition: attachment; filename="filename.xls"

四、文件流

如果需要使用post请求,且后端返回是一个文件流形式,那么前端需要自己将文件流转成链接,然后下载。 二进制流大概长这样: 适用场景:

  • post请求
  • get请求
  • 多文件

1.请求的方式

注意:不可以使用JQuery,因为JQuery不支持blob类型。

原生js写法

const req = new XMLHttpRequest();
req.open('POST', '/download/excel', true);
req.responseType = 'blob'; //如果不指定,下载后文件会打不开
req.setRequestHeader('Content-Type', 'application/json');
req.onload = function() 
    var content = req.getResponseHeader("Content-Disposition") ;
    // 文件名最好用后端返的Content-disposition
    // 需要后端设置 Access-Control-Expose-Headers: Content-disposition 使得浏览器将该字段暴露给前端
    var name = content && content.split(';')[1].split('filename=')[1];
    var fileName = decodeURIComponent(name)
    downloadFile(req.response,fileName)
;
req.send( JSON.stringify(params));

axios写法

download(url: string, body: any, fileName: string, method?) 
	return axios(
	  method: method ||'post',
	  headers: 
	    'Content-Type': 'application/json; charset=utf-8'
	  ,
	  url,
	  responseType: 'blob',
	  headers:  //如果需要权限下载的话,加在这里
	        Authorization: '123456'
	    
	  data: JSON.stringify(params),
	  timeout: 60 * 1000
	).then((res: any) => 
	   if (!res) 
	     message.error('下载失败')
	     return
	   
	   console.log('res:', res)
	   let url = window.URL.createObjectURL(new Blob([res],  type: 'application/vnd.ms-excel' ))
	   let link = document.createElement('a')
	   link.style.display = 'none'
	   link.href = url
	   if (!fileName || typeof fileName != "string") 
	     fileName = "下载文件"
	   
	   link.setAttribute('download', fileName + '.xlsx')
	   document.body.appendChild(link)
	   link.click()
	   document.body.removeChild(link); //下载完成移除元素
	   window.URL.revokeObjectURL(url); //释放掉blob对象
	 )

2.文件下载的方式

通过URL.createObjectURL()下载

URL.createObjectURL() 静态方法会创建一个DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的document绑定。

downloadFile:function(data,fileName)
    // data为blob格式
    var blob = new Blob([data]);
    var downloadElement = document.createElement('a');
    var href = window.URL.createObjectURL(blob);
    downloadElement.href = href;
    downloadElement.download = fileName;
    document.body.appendChild(downloadElement);
    downloadElement.click();
    document.body.removeChild(downloadElement);
    window.URL.revokeObjectURL(href);

通过# FileReader.readAsDataURL()下载

readAsDataURL() 方法会读取指定的 Blob 或 File 对象。读取操作为异步操作,当读取完成时,可以从onload回调函数中通过实例对象的result属性获取data:URL格式的字符串(base64编码),此字符串即为读取文件的内容,可以放入a标签的href属性中。

downloadFile:function(data,fileName)
   const reader = new FileReader()
   // 传入被读取的blob对象
   reader.readAsDataURL(data)
   // 读取完成的回调事件
   reader.onload = (e) => 
       let a = document.createElement('a')
       a.download = fileName
       a.style.display = 'none'
       // 生成的base64编码
       let url = reader.result
       a.href = url
       document.body.appendChild(a)
       a.click()
       document.body.removeChild(a)
   

两者的区别

  • 返回值

FileReader.readAsDataURL(blob)可以得到一段base64的字符串
URL.createObjectURL(blob)得到的是当前文件的一个内存url

  • 内存

FileReader.readAsDataURL(blob)依照js垃圾回收机制自动从内存中清理 URL.createObjectURL(blob)存在于当前document内,清除方式通过revokeObjectURL()手动清除

  • 执行方式

FileReader.readAsDataURL(blob)通过回调的方式f返回,异步执行
URL.createObjectURL(blob) 直接返回,同步执行

  • 多个文件

FileReader.readAsDataURL(blob)同时处理多个文件时,需要一个文件对应一个FileReader对象
URL.createObjectURL(blob) 依次返回,没有影响

  • 优势对比

URL.createObjectURL(blob)得到本地内存容器的URL地址,方便预览,需要注意手动释放内存的问题,性能优秀。
FileReader.readAsDataURL(blob)可直接转为base64格式,直接用于业务

五、插件downloadjs

下载

 npm install --save downloadjs

引入插件

import download from "downloadjs"
// or
const download = require('downloadjs')

使用

  export const downloadFile = (res, type, filename) => 
    // 将二进制流转成blob对象
    const blob = new Blob([res], 
      type: type
    )
    // 调用插件方法
    download(blob, filename, type);
  

前端 下载图片功能实现

在写前端项目时,遇到这个问题,以为很简单,但是还是耽误挺长时间的,现记录一下。

前端下载图片有2中方式

一、a标签的download属性

该方法只支持同源图片下载,对于非同源图片只能打开。

<a href="/images/myw3schoolimage.jpg" download="w3logo">

二、blob对象下载
非同源图片下载可以使用该方法。

function downloadImg(){

        function download(blobUrl) {
            var a = document.getElementById(‘down_network_topology‘);
            a.download = ‘‘;
            a.href = blobUrl;
            // a.click();
            // document.body.removeChild(a);
        }
        var url = $("#down_network_topology").attr("down_url");
        var req = new XMLHttpRequest();
        req.open(‘get‘, url, true);
        req.responseType = ‘blob‘;
        req.onload = function() {
            var data = req.response;
            // var blob = new Blob([data],{type: ‘.jpg,.png,.jpeg,.gif,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel‘});
            var blob = new Blob([data],{type: ‘image/jpeg‘});
            var blobUrl = window.URL.createObjectURL(blob);
            download(blobUrl) ;
        };
        req.send();
    }

使用该方法可能存在跨域问题,报错如下:
技术图片

需要修改nginx配置文件,支持跨域即可。



以上是关于前端实现文件下载的方法的主要内容,如果未能解决你的问题,请参考以下文章

前端——JavaScript

覆盖 WooCommerce 前端 Javascript

不通过服务器控件时用前端javascript与c#后台交互的方法

前端面试题 ---- 手撕JavaScript call apply bind 函数(超详细)

python前端JavaScript高级

前端面试问题(JavaScript)