最近需要在下载的请求头中加入token身份验证,所以传统的form或者url直接下载的方式需要调整成使用ajax,以方便在head中放入token等校验信息,最近研究了两种实现方式,中间踩了很多坑(乱码、FileReader.readAsDataURL: Argument 1 does not implement interface Blob.等问题)
一、使用流的方式+XMLHttpReques方式
后端代码:
HSSFWorkbook wb = ...;//此处省略
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-disposition", "attachment;filename=test.xls");
OutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
wb.write(outputStream);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
outputStream.flush();
outputStream.close();
}
}
前端代码:
function downloada(url,filename) {
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.setRequestHeader('token', 'xxxxxxx'); //用来做身份校验的字符串
xhr.responseType = "blob"; // 设置返回类型blob
// 定义请求完成的处理函数,请求前也可以增加 加载框/禁用下载按钮的相关逻辑
xhr.onload = function() {
if (this.status === 200) {
var blob = this.response;
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = function(e) {
// 转换完成后创建a标签下载
var a = document.createElement('a');
a.download = filename;
a.href = e.target.result;
$("body").append(a);
a.click();
$(a).remove();
}
}
};
xhr.send() //发送ajax请求
}
这种方式可以实现,但是尝试把ajax换成jquery的方式会报错:FileReader.readAsDataURL: Argument 1 does not implement interface Blob,使用XMLHttpReques方式正常可用;
二、使用文件Base64字符串+Jquery Ajax方式实现
后端:
HSSFWorkbook wb = ...; //此处省略
File PDFFilePath = new File("test.xls");
FileOutputStream exportXls = new FileOutputStream(PDFFilePath);
wb.write(exportXls);
exportXls.close();
//自定义方法 文件转base64流
String strResult = PDFToBase64(PDFFilePath);
strResult = strResult.replaceAll("\r\n", "");
//... 根据情况是否要删除创建好的无用文件
return Ret.SUCCESS(strResult); //返回给前端json对象(Ret.SUCCESS是自定义方法,为了返回json对象结构)
前端:
<script src="http://cdn.staticfile.org/FileSaver.js/1.3.8/FileSaver.min.js"></script> //引入FileSaver保存js
//工具方法
function b64toFile(b64Data, filename, contentType) {
let sliceSize = 512;
let byteCharacters = atob(b64Data);
let byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
let slice = byteCharacters.slice(offset, offset + sliceSize);
let byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
let byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
let file = new File(byteArrays, filename, {type: contentType});
return file;
}
//下载时调用的入口方法
function download(){
$.ajax({
url: "http://localhost:81/api/code/uncheck/exportAllGroupTest",
??????type:?"post",
??????dataType:?"json",
??????beforeSend:?function(request){
???????????request.setRequestHeader("Content-Type","application/vnd.ms-excel");
request.setRequestHeader("token","xxxx");
??????},
??????success:?(res)=>{
? console.log("res:"+res);
console.log("base64:"+res.data);
//base64Data 是服务器获取到的数据
let file = b64toFile(res.data, 'test', 'application/vnd.ms-excel;charset=utf-8');
//利用FileSaver.js 下载文件为Excel文件
saveAs(file, "fileName.xls");
}
??});
}
这种方案的实现原理是,后端把文件转换成了base64字符串,前端通过json拿到文件的字符串后进行逆转换下载;
欢迎关注博主,后续不落下博主的干活文章;
|