关于Vue中axios的封装实例详解(2)

const service = axios.create({ // 在向服务器发送请求前,序列化请求数据 transformRequest: [function (data) { data = JSON.stringify(data) return data }], // 在传递给 then/catch 前,修改响应数据 transformResponse: [function (data) { if (typeof data === 'string' && data.startsWith('{')) { data = JSON.parse(data) } return data }] })

拦截器

拦截器,分为请求拦截器以及响应拦截器,分别在请求或响应被 then 或 catch 处理前拦截它们。

之前提到过,由于 async-await 中 catch 难以处理的问题,所以将出错的情况也作为 resolve 状态进行处理。但这带来了一个问题,请求或响应出错的情况下,结果没有数据协议中定义的 msg 字段(消息)。所以,我们需要在出错的时候,手动生成一个符合返回格式的返回数据。

由于,在业务中,没有需要在请求拦截器中做额外处理的需求,所以,请求拦截器的 resolve 状态,只需直接返回就可以了。

请求拦截器代码如下:

// 请求拦截器 service.interceptors.request.use((config) => { return config }, (error) => { // 错误抛到业务代码 error.data = {} error.data.msg = '服务器异常,请联系管理员!' return Promise.resolve(error) })

再来聊聊响应拦截器,还是之前的那个问题,除了请求或响应错误,还有一种情况也会导致返回的消息体不符合协议规范,那就是状态码不为 2 系列或 304 时。此时,我们还是需要做一样的处理——手动生成一个符合返回格式的返回数据。但是,有一点不一样,我们还需要根据不同的状态码生成不同的提示信息,以方便处理上线后的问题。

响应拦截器代码如下:

// 根据不同的状态码,生成不同的提示信息 const showStatus = (status) => { let message = '' // 这一坨代码可以使用策略模式进行优化 switch (status) { case 400: message = '请求错误(400)' break case 401: message = '未授权,请重新登录(401)' break case 403: message = '拒绝访问(403)' break case 404: message = '请求出错(404)' break case 408: message = '请求超时(408)' break case 500: message = '服务器错误(500)' break case 501: message = '服务未实现(501)' break case 502: message = '网络错误(502)' break case 503: message = '服务不可用(503)' break case 504: message = '网络超时(504)' break case 505: message = 'HTTP版本不受支持(505)' break default: message = `连接出错(${status})!` } return `${message},请检查网络或联系管理员!` } // 响应拦截器 service.interceptors.response.use((response) => { const status = response.status let msg = '' if (status < 200 || status >= 300) { // 处理http错误,抛到业务代码 msg = showStatus(status) if (typeof response.data === 'string') { response.data = { msg } } else { response.data.msg = msg } } return response }, (error) => { // 错误抛到业务代码 error.data = {} error.data.msg = '请求超时或服务器异常,请检查网络或联系管理员!' return Promise.resolve(error) })

tips:友情提示,上面那一坨 switch-case 代码,可以使用策略模式进行优化~

支持 TypeScript

由于前段时间,我在部门内推了 TypeScript,为了满足自己的强迫症,将所有 js 文件改写为了 ts 文件。由于 axios 本身有 TypeScript 相关的支持,所以只需要把对应的类型导入,然后赋值即可。

完整代码

// http.ts import axios, { AxiosRequestConfig, AxiosResponse } from 'axios' const showStatus = (status: number) => { let message = '' switch (status) { case 400: message = '请求错误(400)' break case 401: message = '未授权,请重新登录(401)' break case 403: message = '拒绝访问(403)' break case 404: message = '请求出错(404)' break case 408: message = '请求超时(408)' break case 500: message = '服务器错误(500)' break case 501: message = '服务未实现(501)' break case 502: message = '网络错误(502)' break case 503: message = '服务不可用(503)' break case 504: message = '网络超时(504)' break case 505: message = 'HTTP版本不受支持(505)' break default: message = `连接出错(${status})!` } return `${message},请检查网络或联系管理员!` } const service = axios.create({ // 联调 baseURL: process.env.NODE_ENV === 'production' ? `/` : '/apis', headers: { get: { 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8' }, post: { 'Content-Type': 'application/json;charset=utf-8' } }, // 是否跨站点访问控制请求 withCredentials: true, timeout: 30000, transformRequest: [(data) => { data = JSON.stringify(data) return data }], validateStatus () { // 使用async-await,处理reject情况较为繁琐,所以全部返回resolve,在业务代码中处理异常 return true }, transformResponse: [(data) => { if (typeof data === 'string' && data.startsWith('{')) { data = JSON.parse(data) } return data }] }) // 请求拦截器 service.interceptors.request.use((config: AxiosRequestConfig) => { return config }, (error) => { // 错误抛到业务代码 error.data = {} error.data.msg = '服务器异常,请联系管理员!' return Promise.resolve(error) }) // 响应拦截器 service.interceptors.response.use((response: AxiosResponse) => { const status = response.status let msg = '' if (status < 200 || status >= 300) { // 处理http错误,抛到业务代码 msg = showStatus(status) if (typeof response.data === 'string') { response.data = {msg} } else { response.data.msg = msg } } return response }, (error) => { // 错误抛到业务代码 error.data = {} error.data.msg = '请求超时或服务器异常,请检查网络或联系管理员!' return Promise.resolve(error) }) export default service

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/c8e4bef209ec6c9812b950eecc38f175.html