20210329
文件下载方法汇总
1、单文件下载
1.1 方法一:window.open
适用范围:
- 1、已经有了文件在服务器上的存储地址
- 2、文件类型不是图片也不是pdf,也不是.mp3等可以直接被浏览器以预览形式打开的文件类型。
- 3、需要打开一个新的tab页
代码:
这个重点其实不在前端方法,而在于文件服务器的配置。
以nginx为例
// nginx.conf
http {
// ... 一些默认配置,安装nginx就帮你写好的不用管
server {
listen 8080;
server_name citybrain;
location /fileDownload {
add_header Content-Disposition: 'attachment';
add_header Content-Type application/octet-stream;
root /data/file/;
}
}
}
// 注意这里要用 window.open
const url = 'http://localhost:8080/fileDownload/example.zip';
window.open(url);
不要使用window.location.href = url;
下载。
会有两个问题:
- 1、会被项目中的路由router相关的js代码拦截到
- 2、即便router给放过去了,也成功下载了,用户要查看原来的页面还有做
后退
操作,太麻烦了。
1.2 方法二:二进制流转化
适用范围:
- 1、文件通过接口二进制流的形式返回
- 2、有明确的文件类型
- 3、不需要打开一个新的tab页
代码:
// blob.js axios配置
import axios from 'axios';
const blob = axios .create({
baseURL: process.env.VUE APP_ BASE_ API, // url = base url + request url
withCredentials: true, // send cookies when cross - domain requests
timeout:60000, //request timeout
responseType: ' blob'
});
blob.interceptors.request.use(
config => config ,
error => {
// do something with request error
console. log(error)。// for debug
return Promise.reject(error)
}
)
blob.interceptors.response.use(
response => {
const res = response.data;
if (res) {
return res;
} else {
Message.error({
content: ' 数据接口异常,请联系管理员! ',
duration: 5,
return Promise. reject(new Error(' Error'));
});
}
},
error => {
console.log('err' + error). // for debug
Message.error({
content: '数据接口异常,请联系管理员!',
duration: 5
})
return Promise.reject(error);
}
)
export default blob;
// 获取二进制流的接口
export function downloadExcel(params) {
return blob({
url: '',
method: 'post',
data: Qs.stringify(param)
})
}
// 将二进制流转换为文件
downloadExcel(param).then((res) => {
if (!res) return;
let title = '文件名称.excel';
downloadFile(res, title, 'application/vnd.ms-excel;charset=UTF-8');
});
function downloadFile(data, title, type) {
let blob = new Blob([res], {
type: type
});
if (navigator.msSaveOrOpenBlob) {
navigator.msSaveOrOpenBlob(blob, title);
} else {
let url = window.URL.createobjectURL(
blob
);
let link = document.createElement('a');
link.style.display = 'none';
link.href = url;
link.download = title;
document.body.appendchild(link);
link.click();
}
}
1.3 方法三:url下载
本质上是1.1和1.2方法的综合.
适用范围:
- 1、已经有了文件在服务器上的存储地址
- 2、文件类型不是图片也不是pdf,也不是.mp3等可以直接被浏览器以预览形式打开的文件类型。
- 3、不需要打开一个新的tab页
- 4、文件不能跨域
代码:
/**
* @description 根据url下载而不是预览(这种写法会有跨域问题)
* @param {*} url
* @param {*} callback回调方法
* @param {*} options { responseType: 'blob', name: ' 文件名.suffix'}
*/
export function fileAjax(url, callback, options) {
let xhr = new XMLHttpRequest();
xhr.open(' get', url, true);
if (options .responseType) {
xhr.responseType = options.responseType;
}
xhr.onreadystatechange = function() {
if (xhr.readystate === 4 && xhr.status === 200) {
downloadFile(xhr.response, options.name);
if (callback && typeof callback === ' function') {
callback(xhr);
}
}
xhr.send();
}
function downloadFile(content, filename) k
window.URL = window.URL || window.webkitURL;
let a = document. createElement( 'a' );
let blob = new Blob([content]);
//通过二进制文件创建url
let url = window.URL.createobjectURL(blob);
a.href = url;
a. download = filename ;
a.click( );
//销毁创建的url
window.URL.revoke0bjectURL (url);
}
TIPS:可能会遇到的问题
1、pdf, 图片等,使用window.open方法会被浏览器认为是预览而不是下载.
解决方法:
export function downloadByUrl(url, fileName) {
let dom_a = document.createElement('a');
dom_a.href = url;
dom_a.download = filename; // 控制仅下载不预览的重要属性
dom_a.click();
//销毁生成的dom
dom_a.remove();
}
不过,很奇怪的事,上面这个方法在chrome中总是时好时坏。
2、多文件/批量下载
实现多文件下载,本质上是将多文件转化为单文件下载。
有两种思路:
- 1、后端将多个文件整合成一个压缩包文件.zip,然后给前端下载
- 2、前端多次调用单文件下载接口,由前端将获取的二进制流合成一个压缩包.
2.1 window.open
后端将多个文件整合成一个压缩包文件.zip,然后给前端下载
适用范围:
- 1、已经有了文件在服务器上的存储地址
- 2、文件类型不是图片也不是pdf,也不是.mp3等可以直接被浏览器以预览形式打开的文件类型。
- 3、需要打开一个新的tab页
代码:
window.open(url);
2.2 二进制流转化
后端将多个文件整合成一个压缩包文件.zip,然后给前端下载
实际上和1.2的二进制流转化是一模一样的,只不过最后下载的结果是一个包含多个文件的压缩包.zip文件
适用范围:
- 1、文件通过接口二进制流的形式返回
- 2、有明确的文件类型
- 3、不需要打开一个新的tab页
代码
// 接口中获取二进制流
// ...省略
// 将二进制流转换为文件
downloadExcel(param).then((res) => {
if (!res) return;
let title = '文件名称.zip';
downloadFile(res, title, 'application/zip');
});
function downloadFile(data, title, type) {
let blob = new Blob([res], {
type: type
});
if (navigator.msSaveOrOpenBlob) {
navigator.msSaveOrOpenBlob(blob, title);
} else {
let url = window.URL.createobjectURL(
blob
);
let link = document.createElement('a');
link.style.display = 'none';
link.href = url;
link.download = title;
document.body.appendchild(link);
link.click();
}
}
2.3 使用jszip插件
前端多次调用单文件下载接口,由前端将获取的二进制流合成一个压缩包.
https://stuk.github.io/jszip/
适用范围
1、能够将多文件下载转化成多个单文件下载
比如,你已经有了多个下载单文件的url
npm install file-saver jszip -S
代码:
import { saveAs } from 'file-saver';
let JSZIP = require('jszip');
// for 循环调用接口 获取二进制流
let blobList = [...];
// 调用jszip方法进行压缩
function compressZip(zipName, blobList) {
let jsZip = new JSZIP();
blobList.forEach((item, index) => {
jsZip .file(`文件名${index}.png`, item)
});
jsZip.generateAsync({type:"blob"})
.then(function(content) {
// see FileSaver.js
saveAs(content, zipName);
});
}
实际上我是使用失败了的。不知道是什么问题.如果下次还有机会使用的话可以看官网文档尝试一下.