Axios 请求拦截处理
// 响应拦截器
instance.interceptors.response.use(async (response: AxiosResponse<customRes, any>): Promise<any> => {
// 文件流处理
if (response.config.responseType == "blob") return Promise.resolve(response);
return Promise.resolve(response.data);
}, responseErrorHandle)
当响应的数据类型是文件流(Blob)时,拦截器直接返回了一个包含 response
的 Promise,以便在调用这个接口的地方能够获取到文件流并进一步处理。
请求方法处理
通过 Axios 请求文件流(Blob)并进行文件下载的函数。
请求服务器返回的文件流数据,并通过浏览器的下载机制将其保存到本地文件。
设置响应类型为 Blob 是为了告知服务器返回的数据是二进制流,方便后续在客户端进行文件下载。
/**
* 返回文件流测试
*/
export const getFile = () => {
instance.get('/test/file/stream', {
responseType: "blob", // 设置响应类型为blob
params: {}
}).then((response) => {
// 处理下载文件
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", getFileNameFromHeaders(response)); // 设置下载的文件名和扩展名
link.click();
})
}
从headers中取出文件名方法封装
// 文件名处理
export const getFileNameFromHeaders = (response: AxiosResponse) => {
// 从响应头中获取Content-Disposition信息
const contentDisposition = response.headers['content-disposition'];
// 使用正则表达式匹配文件名
const match = /filename="(.*)"/.exec(contentDisposition);
// 获取匹配的文件名
return match ? decodeURI(match[1]) : 'unknown'
}
instance.get('/test/file/stream', {...})
:
- 使用 Axios 的
get
方法向服务器端发送 GET 请求,请求的地址是 '/test/file/stream'。responseType: "blob"
:
- 在请求配置中设置
responseType
为 "blob",表示期望服务器响应的数据是二进制数据(Blob 对象)。.then((response) => {...})
:
- 使用 Promise 的
.then
处理请求成功的回调函数,response
包含了从服务器返回的 Blob 对象。window.URL.createObjectURL(new Blob([response.data]))
:
- 通过
window.URL.createObjectURL
创建一个临时的 URL,该 URL 表示了从服务器返回的 Blob 对象的内容。这个 URL 通常用于创建下载链接。const link = document.createElement("a");
:
- 创建一个
<a>
元素,用于模拟文件下载。link.href = url;
:
- 将刚刚创建的 URL 赋值给
<a>
元素的href
属性。link.setAttribute("download", getFileNameFromHeaders(response));
:
- 设置
<a>
元素的download
属性为从服务器响应头中获取的文件名。这里使用getFileNameFromHeaders
的函数,它可能用于从响应头中获取文件名,确保文件名包含在Content-Disposition
头中。link.click();
:
- 模拟点击
<a>
元素,触发文件下载。整个流程的目的是通过 Axios 请求获取服务器端返回的文件流,然后使用 Blob 对象创建一个临时的 URL,并通过创建
<a>
元素模拟点击以触发文件下载。
网络服务处理
返回文件流的接口
// 服务端返回文件流,并将文件名通过 attachment 返回
router.get('/file/stream', async (ctx, next) => {
const filePath = path.join(__dirname, '../upload/file/测试表格.xlsx');
// 设置响应头,告诉浏览器文件名
ctx.attachment(encodeURI('测试表格.xlsx'));
// 读取文件流并设置为响应体
ctx.body = await fs.createReadStream(filePath);
})
跨域配置
允许前端访问 Content-Disposition
app.use(cors({
exposeHeaders: ['Content-Disposition'],
credentials: true, // 允许携带cookies
}));
总结
服务端返回文件流,并将文件名通过 attachment 返回,文件名会被携带在 Content-Disposition中。
前端通过 getFileNameFromHeaders 方法取出 文件名
前端通过 window.URL.createObjectURL(new Blob([response.data])) 创建一个可用于浏览器中的文件下载的 URL