说明
实际应用中,经常用到axios这个库。这里简要记载一下下载的用法。
Ajax无刷新式下载
通常我们采用document.location='downloadUrl’来下载文件,这样会刷新页面,体验不好。下面的方式能直接下载。
function downloadFile(url, filename) {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true); // 也可以使用POST方式,根据接口
xhr.setRequestHeader('token', sessionStorage.getItem('token')); // 设置token
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
xhr.responseType = 'blob'; // 返回类型blob
xhr.onload = function(e) {
if (this.status === 200) {
contentDisposition = xhr.getResponseHeader('Content-Disposition')
_filename = contentDisposition.substring('attachment;filename='.length)
_filename = decodeURIComponent(_filename)
// console.log(_filename)
const blob = this.response;
const reader = new FileReader();
reader.readAsDataURL(blob); // 转换为base64,可以直接放入a表情href
reader.onload = function(e) {
const a = document.createElement('a');
a.download = _filename;
a.href = e.target.result;
document.documentElement.appendChild(a);
a.click();
a.remove();
};
}
};
xhr.send(); // 发送ajax请求
}
axios下载文件
基本写法:
axios({
url: 'http://localhost:5000/static/example.pdf',
method: 'GET',
responseType: 'blob', // important
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.pdf');
document.body.appendChild(link);
link.click();
});
vue3中封装一下
public download<T, P>(url: string, filename: string): Promise<P> {
const config = {
method: 'get',
url
} as PureHttpRequestConfig;
return new Promise((resolve, reject) => {
PureHttp.axiosDownloadInstance
.request(config)
.then((response: any) => {
const blob = response.data;
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = function(e) {
const a: any = document.createElement('a');
a.download = filename + '.pdf';
a.href = e.target.result;
document.documentElement.appendChild(a);
a.click();
a.remove();
}
resolve(response);
})
.catch(error => {
reject(error);
});
});
}
后端输出二进制流
这里以Java的SpringBoot为例。
try {
BufferedOutputStream out = new BufferedOutputStream(response
.getOutputStream());
ByteArrayOutputStream byteout = new ByteArrayOutputStream();
Html2PDFUtil pdfUtil = new Html2PDFUtil();
pdfUtil.toPDF(content, byteout, page.getFromUrl());
//pageTitle = pdfMaker.parseTitle(pageTitle);
String filename = PageUtil.cleanTitle(pageTitle) + ".pdf";
//解决下载文件名为乱码的问题
//然后就是headers.add("Content-disposition","attachment;filename="+URLEncoder.encode("中国","UTF-8")+".txt;
// filename*=UTF-8''"+URLEncoder.encode("中国","UTF-8")+".txt");
//filename和filename*可以组合使用来解决跨浏览器的问题。
//pageTitle = URLEncoder.encode(pageTitle, "UTF-8");
//new String(fileName.getBytes(), "ISO8859-1")
byte[] data = byteout.toByteArray();
response.setContentType("application/pdf;charset=UTF-8"); //"application/x-download
//String contentDisposition = "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")
// + ";filename*=UTF-8''" + URLEncoder.encode(filename, "UTF-8");
String contentDisposition = "attachment;filename=" + URLEncoder.encode(filename, "UTF-8");
response.setHeader("Content-Disposition", contentDisposition);
response.setHeader("Access-Control-Expose-Headers", "Content-disposition");
out.write(data, 0, data.length);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
注意,如果让前端获取response头中的文件名也是可以的,但简便的做法是直接从前端拿,一般文件名在下载时已经确定了。