import axios from 'axios'
import { TOKEN } from '#/utils/config'
const genFetch = (opts = {}) => {
//xxx为某变量
return axios.create({
baseURL: xxxxx ? xxxxx+ 'api' : '/api',
timeout: Infinity,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
...opts
})
}
/**
* API
* @param {object} Vue Vue
* @param {object} opts 选项
* {
* notice?: (msg) => void
* router?: VueRouterInstance
* }
*
* @example
export default {
async beforeMount () {
try {
const { error, model } = await this.$api('/role2', {
// 声明自己处理请求状态错误,需要try catch
$skipGlobalErrorCheck: true
})
if (error) {
// 这里的错误是接口给的逻辑错误
console.error('Biz Err: ', error, model)
return
}
console.log('Done. ', model)
} catch (err) {
// 这里的错误是请求时错误,比如404,500等
console.log('Err: ', err.message)
}
}
}
*
*
* @returns
*/
const Request = (Vue, opts) => {
if (Request.installed) {
return
}
const showMessage =
Object.prototype.toString.call(opts.notice) === '[object Function]'
? opts.notice
: (msg) => {
console.warn('无法处理错误,未设置notice选项...')
console.error(msg)
}
const buildErrorMessage = (response) => {
if (!response) {
return '未知错误'
}
return response.status ?? response.data?.model ?? response.data ?? response.statusText ?? response
}
const buildErrorResponse = (response) => {
return { error: true, model: buildErrorMessage(response) }
}
const buildNormalResponse = (data) => {
return { error: !data.success, model: data.data || data.message }
}
const $api = genFetch({
timeout: 15000
})
$api.interceptors.request.use((request) => {
if (!request.headers.Authorization) {
// 加token
const token = window.localStorage.getItem(TOKEN)
if (token) {
request.headers.Authorization = `Bearer ${token}`
}
}
return request
})
$api.interceptors.response.use(
(response) => {
const { config } = response
// xxx为特殊格式转换
if (config.url.startsWith('/xxx/')) {
response.data = { success: response.data.ok, message: response.data.msg, data: response.data }
}
// $skipGlobalResponseWrap 跳过全局响应包装步骤,获取原始响应信息
const respData = config.$skipGlobalResponseWrap ? { data: response, success: true } : response.data
return response.status === 200 ? buildNormalResponse(respData) : buildErrorResponse(response)
},
(error) => {
// 包装错误信息
const msg = axios.isCancel(error) ? '超时取消请求' : buildErrorMessage(error.response ?? error.status ?? error.message)
const err = new Error(msg)
// 用户指定跳过默认错误处理
if (error.config.$skipGlobalErrorCheck) {
// 往上抛出包装后的错误
return Promise.reject(err)
}
if (error.response) {
switch (error.response.status) {
// 401,403: 跳转到登录页
case 401:
case 403: {
if (typeof opts.router !== 'undefined') {
// 有router的环境
opts.router.replace({ name: 'login' })
} else {
console.warn('无法跳转到登录页,未设置router选项...')
}
showMessage('用户会话已失效,请重新登录')
break
}
case 404: {
showMessage('调用了不存在的接口,请检查')
break
}
case 500: {
showMessage('接口异常')
break
}
default: {
showMessage(`其他错误, Error Code: ${error.response.status}`)
break
}
}
}
// 扶正错误
return Promise.resolve(buildErrorResponse({ statusText: msg }))
}
)
Vue.prototype.$api = $api
// 兼容现有的代码
// 最好将现有的请求接口相关的代码都更新为如下处理方式:
// const { error, model } = await this.$api('/xxx/xxx', {
// params
// })
// if (error) {
// this.$Modal.error({
// title: '提示',
// content: `加载xx错误!原因:${model}`
// })
// return
// }
// console.log(model)
const api = genFetch()
api.interceptors.request.use((request) => {
if (!request.headers.Authorization) {
// 加token
const token = window.localStorage.getItem(TOKEN)
if (token) {
request.headers.Authorization = `Bearer ${token}`
}
}
return request
})
api.interceptors.response.use(
(response) => {
return response.data.model ? response.data.model : response.data
},
(error) => {
return Promise.reject(error)
}
)
Vue.prototype.fetch = api
Request.installed = true
}
export default Request
main.js中的引用
import Request from './utils/request'
实际调用
try {
const { error, model } = await this.$api.get(' xxxxx',
{
params:{
xxxxx: xxxxxx,
},
})
if (error) {
// 这里的错误是接口给的逻辑错误
this.$Modal.error({
title: '提示',
content: `查询同步任务错误!原因:${model.msg? model.msg : model}`,
})
return
}
} catch (err) {
// 这里的错误是请求时错误,比如404,500等
console.log('Err: ', err.message)
}
感觉相对比较完善,记录一下,不喜勿喷,(#^.^#)