我们知道,超链接如果直接链接到后端下载文件接口的路由,那么可以直接进行文件下载。那是因为浏览器会直接判断返回的数据类型(Response),但是,异步请求的话,返回的数据是交给异步请求来处理的,不是浏览器,所以不能够直接进行下载操作。
传统的Ajax请求
下载是浏览器的内置事件,而ajax请求将response交给了js来处理,而ajax只能处理接收的字符串进行处理,所以我们请求的是服务器返回的有中文乱码的二进制数据流
axios请求
axios请求可以接收二进制数据流,将responseType:'blob'添加至请求中即可,然后返回的二进制数据流进行处理,再触发浏览器的下载功能即可
演示
后端
@RequiresRoles("admin")
@GetMapping("/downloadGbsExcel")
public void downloadGbsExcel(HttpServletRequest request,HttpServletResponse response) {
List<ExcelGbsInfo> gbsExcel = adminService.getGbsExcel();
ExcelWriter writer = ExcelUtil.getWriter(true);//true为xlsx文件
//设置写出excel别名
writer.setHeaderAlias(ExcelGbsInfo.getheaderAlias());
//将list中的数据,给ExcelWriter处理成Excel文件流
writer.write(gbsExcel);
//设置response请求头
response.reset();//设置页面不缓存,清空buffer
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
// response.setContentType("multiple/form-data");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
response.setHeader("Content-Disposition", "attachment;filename=sx_gb_gs_table.xlsx");
ServletOutputStream out ;
try {
out = response.getOutputStream();
writer.flush(out);//将处理的Excel写入到输出流
out.close();
} catch (IOException e) {
e.printStackTrace();
}
writer.close();
}
我这里是进行的excel下载,使用的hutool工具多excel数据进行封装,需要注意的是,如果是前后端分离项目,一定要加上:response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
这句,否则会出现:
Access to XMLHttpRequest at 'http://localhost:8081/admin/downloadGbsExcel' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
这样的错误提示,我这里下载的是excel所以请求类型是hutool提供的excel下载内容类型
前端
this.$axios({
method: 'get',
responseType:'blob', //返回类型
url: '/admin/downloadGbsExcel',
headers: {
"Authorization": localStorage.getItem("token")
},
}).then(data=>{
//通过返回的二进制流创建 Blob对象
let blob = new Blob([data.data],
{type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}
);
let url = window.URL.createObjectURL(blob);
//方式一:该url就是由返回的二进制流创建的文件下载地址,可以直接使用 window.location.href = url;下载
//不过下载后需要手动修改文件名和后缀名
//方式二:触发浏览器的内置下载功能
let a = document.createElement('a')//创建一个a标签元素
a.style.display = 'none'//设置为不显示
a.href = url //设置a标签的href属性
a.setAttribute('download', '*干事表.xlsx')//设置下载的文件名
document.body.appendChild(a)//将a标签元素加入到页面中
a.click()//触发点击
document.body.removeChild(a) // 下载完成移除元素
window.URL.revokeObjectURL(url) // 释放掉blob对象
})
通过触发该请求,完成了和a标签点击下载一样的效果!!!