1.实现下载文件函数
ts版本
import { AxiosResponse } from "axios";
export const DonwloadFile = (response: AxiosResponse, fileName = 'file') => new Promise((resolve) => {
const fileReader = new FileReader()
let queryFileName = fileName
if (response.headers['content-disposition']) {
queryFileName = decodeURI(response.headers['content-disposition'].split(';')[1].split('filename=')[1])
}
fileReader.onload = () => {
const blob = new Blob([response.data], {
type: response.data.type,
});
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.setAttribute("download", queryFileName ?? fileName);
document.body.appendChild(link)
link.click()
// 释放资源
URL.revokeObjectURL(link.href)
document.body.removeChild(link)
resolve(response.data)
}
fileReader.readAsText(response.data)
})
这里的
queryFileName
对后端响应头中的content-disposition
有关但是,该代码支持的
传输格式
如下content-disposition: attachment;filename=文件名.文件类型
若出现获取不到
content-disposition
需要要求后端暴露对应的响应头Access-Control-Expose-Headers: xxxxxx,……, Content-Disposition
若需要JS版本,只需要将对应的:
后面的类型删除即可
2.添加axios响应拦截器
为方面后续所有文件的下载,所以采用了直接拦截 所有请求
当然,我们不单单只对文件进行处理,通常在这里还可以进行错误的统一抛出
import { clearAuthStorage, getToken, getUserInfo } from "@utils/auth/user";
import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
import { useRouterPush } from "@/hooks/common";
import { DonwloadFile } from "../common/file";
export const createAxiosByInterceptors = (config?: AxiosRequestConfig): AxiosInstance => {
const instance: AxiosInstance = axios.create({
timeout: Number(window.__ENV__.VUE_APP_TIME_OUT),
withCredentials: true,
baseURL: window.__ENV__.VUE_APP_BASE_URL,
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
...config,
});
// 添加请求拦截器
instance.interceptors.request.use(
(axiosConfig) => {
const config: AxiosRequestConfig = { ...axiosConfig };
config.headers.Authorization = getToken();
return config;
},
(error) => Promise.reject(error),
);
// 添加响应拦截器
instance.interceptors.response.use(
// 正常响应数据
(response) => {
const { code, data, message } = response.data;
if (response.data instanceof Blob) {
return DonwloadFile(response);
}
if (Number(code) >= 200 && Number(code) <= 299) {
return data;
}
if (code === 401 || code === 409) {
window.$message.error(message);
window.localStorage.clear();
jumpLogin();
return "未登录";
}
window.$message.error(message);
return Promise.reject(response.data);
},
// 响应的错误
(err) => {
if (err.response) {
if (err.response.status === 401 || err.response.status === 409) {
jumpLogin();
}
}
window.$message.error(err?.response?.data?.message || "请求失败,请检查后重试");
return Promise.reject(err);
},
);
return instance;
};
当然,如果你只需要一个简单的版本也可以直接用下面这个代码
const instance = axios.create({ timeout: 1000, withCredentials: true, baseURL: "你需要请求的地址", }); instance.interceptors.response.use( // 正常响应数据 (response) => { const { code, data, message } = response.data; if (response.data instanceof Blob) { return DonwloadFile(response); } } )
3.请求下载文件接口
这里的核心代码就是{ responseType: "blob" }
post版本
若需要在下载文件时,传递对应数据到后端则需要使用post版本的下载文件
/** 测试点样例文件 */
export function getZipTestCase(requestData: TopicVO.topicDetail) {
const responseData = web.post("请求路径", requestData, { responseType: "blob" });
return responseData;
}
get版本
通常,我们在下载文件时只需要告诉后端我需要文件即可。
export function downloadInvigilator() {
const responseData = web.get("/user/download", { responseType: "blob" });
return responseData
}