在若依项目中,它自己封装好了 download 下载方法,但是因为设置了 Content-Type 是 application/x-www-form-urlencoded ,因为浏览器限制,导致传值的时候,数据过大就会报错。
关键代码:src/utils/request.js 文件
// 传json的下载方法
export function downloadByJson(url, params, filename, config) {downloadLoadingInstance = ElLoading.service({ text: "正在下载数据,请稍候", background: "rgba(0, 0, 0, 0.7)", })return service.post(url, params, {// 主要是要设置这个responseType: 'blob',...config}).then(async (data) => {const isBlob = blobValidate(data);if (isBlob) {const blob = new Blob([data])saveAs(blob, filename)} else {const resText = await data.text();const rspObj = JSON.parse(resText);const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']ElMessage.error(errMsg);}downloadLoadingInstance.close();}).catch((r) => {console.error(r)ElMessage.error('下载文件出现错误,请联系管理员!')downloadLoadingInstance.close();})
}
src/utils/request.js 文件的完整代码
import axios from 'axios'
import { ElNotification , ElMessageBox, ElMessage, ElLoading } from 'element-plus'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { tansParams, blobValidate } from '@/utils/ruoyi'
import cache from '@/plugins/cache'
import { saveAs } from 'file-saver'
import useUserStore from '@/store/modules/user'let downloadLoadingInstance;
// 是否显示重新登录
export let isRelogin = { show: false };axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 对应国际化资源文件后缀
axios.defaults.headers['Content-Language'] = 'zh_CN'
// 创建axios实例
const service = axios.create({// axios中请求配置有baseURL选项,表示请求URL公共部分baseURL: import.meta.env.VITE_APP_BASE_API,// 超时timeout: 1800000
})// request拦截器
service.interceptors.request.use(config => {// 是否需要设置 tokenconst isToken = (config.headers || {}).isToken === false// 是否需要防止数据重复提交const isRepeatSubmit = (config.headers || {}).repeatSubmit === falseif (getToken() && !isToken) {config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改}// get请求映射params参数if (config.method === 'get' && config.params) {let url = config.url + '?' + tansParams(config.params);url = url.slice(0, -1);config.params = {};config.url = url;}if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {const requestObj = {url: config.url,data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,time: new Date().getTime()}const sessionObj = cache.session.getJSON('sessionObj')if (sessionObj === undefined || sessionObj === null || sessionObj === '') {cache.session.setJSON('sessionObj', requestObj)} else {const s_url = sessionObj.url; // 请求地址const s_data = sessionObj.data; // 请求数据const s_time = sessionObj.time; // 请求时间const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {const message = '重复请求,过滤!';console.warn(`[${s_url}]: ` + message)// return Promise.reject(new Error(message))} else {cache.session.setJSON('sessionObj', requestObj)}}}return config
}, error => {console.log(error)Promise.reject(error)
})// 响应拦截器
service.interceptors.response.use(res => {// 未设置状态码则默认成功状态const code = res.data.code || 200;// 获取错误信息const msg = errorCode[code] || res.msg || res.data.msg || errorCode['default']// 二进制数据则直接返回if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {return res.data}if (code === 401) {if (!isRelogin.show) {isRelogin.show = true;ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {isRelogin.show = false;useUserStore().logOut().then(() => {location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index';})}).catch(() => {isRelogin.show = false;});}return Promise.reject('无效的会话,或者会话已过期,请重新登录。')} else if (code === 500) {ElMessage({ message: msg, type: 'error' })return Promise.reject(new Error(msg))} else if (code === 601) {ElMessage({ message: msg, type: 'warning' })return Promise.reject(new Error(msg))} else if (code !== 200) {ElNotification.error({ title: msg })return Promise.reject('error')} else {return Promise.resolve(res.data)}},error => {console.log('err' + error)let { message } = error;if (message == "Network Error") {message = "网络异常";} else if (message.includes("timeout")) {message = "系统接口请求超时";} else if (message.includes("Request failed with status code")) {message = "系统接口" + message.substr(message.length - 3) + "异常";}ElMessage({ message: message, type: 'error', duration: 5 * 1000 })return Promise.reject(error)}
)// 传json的下载方法
export function downloadByJson(url, params, filename, config) {downloadLoadingInstance = ElLoading.service({ text: "正在下载数据,请稍候", background: "rgba(0, 0, 0, 0.7)", })return service.post(url, params, {responseType: 'blob',...config}).then(async (data) => {const isBlob = blobValidate(data);if (isBlob) {const blob = new Blob([data])saveAs(blob, filename)} else {const resText = await data.text();const rspObj = JSON.parse(resText);const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']ElMessage.error(errMsg);}downloadLoadingInstance.close();}).catch((r) => {console.error(r)ElMessage.error('下载文件出现错误,请联系管理员!')downloadLoadingInstance.close();})
}// 通用下载方法
export function download(url, params, filename, config) {downloadLoadingInstance = ElLoading.service({ text: "正在下载数据,请稍候", background: "rgba(0, 0, 0, 0.7)", })return service.post(url, params, {transformRequest: [(params) => { return tansParams(params) }],headers: { 'Content-Type': 'application/x-www-form-urlencoded' },responseType: 'blob',...config}).then(async (data) => {const isBlob = blobValidate(data);if (isBlob) {const blob = new Blob([data])saveAs(blob, filename)} else {const resText = await data.text();const rspObj = JSON.parse(resText);const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']ElMessage.error(errMsg);}downloadLoadingInstance.close();}).catch((r) => {console.error(r)ElMessage.error('下载文件出现错误,请联系管理员!')downloadLoadingInstance.close();})
}export default service
blobValidate 方法:(在src/utils/ruoyi.js里)
// 验证是否为blob格式
export function blobValidate(data) {return data.type !== "application/json";
}
main.js (src/main.js 挂载到全局上)
import { createApp } from "vue";
import { download,downloadByJson } from "@/utils/request";...
const app = createApp(App);
app.config.globalProperties.downloadByJson = downloadByJson;
使用:
const {proxy} = getCurrentInstance();function download(){ proxy.downloadByJson("sales/...地址/export",{"advancedList": searchValue.value,"param": queryParams.value},`名字_${new Date().getTime()}.xlsx`);
}