通过 fetch 发送 post 请求下载文件

1 案例

通过 fetch 发起请求获取文件,再用 Blob 对象来接收处理。接收到后端返回的文件后,将其放入 a 标签 的 href,并触发下载行为。实现的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const formData = new FormData();
formData.append("msg", "download");

fetch(url, {
method: "POST",
body: formData,
headers: new Headers({ "Content-Type": "application/json;charset=UTF-8" }),
})
.then((response) => {
return response.blob();
})
.then((blob) => {
const link = document.createElement("a");
link.style.display = "none";
link.href = URL.createObjectURL(blob);
document.body.appendChild(link);
link.click();
// 释放的 URL 对象并移除 a 标签
URL.revokeObjectURL(link.href);
document.body.removeChild(link);
});

注意:调用 response 的 blob 方法会返回一个 promise 对象

2 处理文件名

上一个步骤下载得到的文件名是无意义的。假设服务端把文件名放在 content-disposition 头:

1
2
3
4
5
response.setContentType("application/octet-stream");
response.setHeader("Access-Control-Expose-Headers", "Content-disposition");
response.setHeader("Content-disposition", "attachment;filename=" + fileName);
response.flushBuffer();
workbook.write(response.getOutputStream());

前端可采用 split 方法提取。完整实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
fetch(url, {
method: "POST",
body: formData,
headers: new Headers({ "Content-Type": "application/json;charset=UTF-8" }),
}).then(function (response) {
const filename = res.headers
.get("content-disposition")
.split(";")[1]
.split("=")[1];

response.blob().then((blob) => {
const link = document.createElement("a");
link.style.display = "none";
link.download = filename;
link.href = URL.createObjectURL(blob);
document.body.appendChild(link);
link.click();
// 释放的 URL 对象并移除 a 标签
URL.revokeObjectURL(link.href);
document.body.removeChild(link);
});
});

注:a 标签的 download 属性就是文件名

或者用 async/await 实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
async function download(url) {
const request = {
method: 'POST',
body: formData,
headers: new Headers({ "Content-Type": "application/json;charset=UTF-8" }),
}

const response = await fetch(url, request)
const filename = response.headers.get('content-disposition').split(';')[1].split('=')[1]
const blob = await response.blob()

const link = document.createElement('a')
link.download = decodeURIComponent(filename)
link.style.display = 'none'
link.href = URL.createObjectURL(blob)
document.body.appendChild(link)
link.click()
URL.revokeObjectURL(link.href)
document.body.removeChild(link)j
}