使用语言:ts
前端框架:angular13
近期工作中遇到一个场景:
在下载文件的时候,后台存在一个安全场景——文件可能有软链接,所以后台在下载文件的时候加了个错误场景,在下载到软链接的时候会返回错误,前台要把错误展示出来。
而前台下载文件的时候,我直接使用的是dom元素,就是a链接,这就有个情况,在软链接的时候,因为链接是失效的,a链接的被自动点击后,页面就会进行跳转而不是下载。
所以要解决这个问题,我提出的方案是:
使用请求的方式请求下载的文件,跟后台做个交互,确认无误了再下载。
- 尝试一:使用请求接口的方式来下载文件
所以我尝试的第一步就是,使用请求接口的方式来下载文件。
downloadZip() {
let url = "/api/zipBoxs/test.zip";
// 下载文件操作(先放这里)
let link: HTMLAnchorElement = document.createElement('a');
let body: any = document.querySelector('body');
link.href = url;
body.appendChild(link);
link.click();
// 尝试请求下载文件的路径
this.http.get(url).subscribe(
(success) => {
console.log('success', success)
},
(err) => {
console.log('err', err)
}
)
}
得到的结果是:
如下图,Unexpected token P in JSON at position 0,此结果其实不影响文件下载成功,只不过就是在请求逻辑中,走了请求失败逻辑,图中是我上面的代码中打印的请求失败内容。
但就觉得怪怪的,毕竟在我们看来,下载文件是成功了的,而且我后面也需要根据请求状态来判断是否要进行文件下载。
- 尝试二:我起初还没有意识到是传递方式出了问题,我为了搞清楚,自己尝试了原生的传递方式,如下:
// xmlHttpRequest 对象,API可以用来发送网络请求
// 1、创建xmlHttpRequest对象
var xhr = new XMLHttpRequest();
// 2、给该对象绑定监听事件,监听网络请求发送过程
xhr.addEventListener('readystatechange',function(){
/*
xhr.readyState用来表示当前请求发送的过程
默认值:0 ==> chr.open 尚未调用
1 ==> xhr.send() 尚未调用
2 ==> 服务器尚未响应
3 ==> 正在接收服务器响应
4 ==> 完成了对服务器响应的接收
*/
if(xhr.readyState == 4){
/*
200-300 代表请求完成
200 成功
304 从缓存获取
4XX 请求配置参数出错
403 被拒绝
5XX 服务器异常
*/
if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304)
// 获取xml格式 xhr.responseXML
// 获取JSON格式
// 注意这里:直到这里,我才意识到,是因为JSON的原因
console.log(JSON.parse(xhr.responseText));
}
})
// 3、配置网络请求参数(url,method)
var method = 'get';
xhr.open(method,url,true); //bool:如果为true 异步请求 响应写在回调里 如果是false 同步请求,请求结束之后执行后面的代码
// 4、请求头配置,发送数据格式
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
// 5、发送网络请求
xhr.send();
该方式明确在请求成功后解析JSON的时候报了错:Unexpected token P in JSON at position 0
- 尝试三:所以我就有了修改请求体的想法,如下:
this.http.get(url,
{
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': '123',
}),
'responseType': 'blob'
}).subscribe(
(success) => {
console.log('success', success)
},
(err) => {
console.log('err', err)
}
)
至此,我再尝试,问题解决,下载成功的时候正确走请求成功逻辑。
最后,让我们回归业务流:将下载文件放到请求成功的逻辑中。
downloadZip() {
let url = "/api/zipBoxs/test2.zip";
this.http.get(url,
{
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': '123',
}),
'responseType': 'blob'
}).subscribe(
(success) => {
let link: HTMLAnchorElement = document.createElement('a');
let body: any = document.querySelector('body');
link.href = url;
body.appendChild(link);
link.click();
},
(err) => {
console.log('err', err)
}
)
}
完美~