-
Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。
-
封装希望达到的效果
- 引用方便,在组件中,通过
this.$http使用 ✅ - 兼容 REST 风格封装,使用 JSON 进行交互,提供常用的四种方法 ✅
- 不同的请求方法,参数格式一直
this.$http.get(url,params)、this.$http.post(url,params)✅ - 错误时,控制台有特别的日志输出,要是公司有条件,可提交到服务器,方便排查问题 ✅
- 统一处理HTTP状态码和跟后端约定好的响应状态码,断网时显示断网组件等 ✅
- 取消请求 ✅
- 重复请求 ✅
- 用户手动取消 ✅
- 清空全部请求 ✅
- 文件下载 ⭕️
- 跨域配置 ✅
- 响应拦截 ⇒ 将http响应信息存入在
httpData属性中,与服务响应信息一起返回 ✅ - mock数据 ⇒ 使用adapter自定义处理请求,mock服务端数据 ✅
- 引用方便,在组件中,通过
-
封装定义
-
src/libs/axios.js import axios from 'axios' import { message as $Message } from 'ant-design-vue'; import { getToken } from '@/utils/tools' import { logInfo, redLog } from '@/utils/log' const baseURL = window.location.protocol + '//xxxx' const instance = axios.create({ baseURL, timeout: 10000 * 5, headers: { Authorization: `xxxx ${getToken()}` } }); // 请求拦截器 const interceptorsRequest = (config) => { console.log('请求拦截器',config) return config } // 请求拦截器-错误处理 const interceptorsRequestFailed = (error) => { return Promise.reject(error) } // 响应拦截器 const interceptorsResponse = (res) => { console.log('响应拦截器',res) return res } // 响应拦截器-错误处理 const interceptorsResponseFailed = (error) => { // 上传错误日志 logInfo(error) redLog(error) return Promise.reject(new Error(error.message)) } instance.interceptors.request.use(interceptorsRequest,interceptorsRequestFailed) instance.interceptors.response.use(interceptorsResponse,interceptorsResponseFailed) export default function request(e) { const { url = '', method = 'GET', data = {}, config = {}, option = {}} = e switch (method.toUpperCase()) { case 'GET': return instance.get(url, { params: data, ...config }) case 'POST': return instance.post(url, data, config) } } -
使用
-
import request from '../libs/axios' // @data 参数 Object // @config 请求配置 export const postRequest = (data, config) => { return request({ // 必填,请求地址 url: '/api/user/media_account/list_shop_account', // 请求参数(get\post)都是一个属性 data, // 请求方式,默认get method: 'POST', // 请求配置 config: { // 传入配置 ...config, // 支持请求配置 https://axios-http.com/zh/docs/req_config }, // 自定义配置项 option: {} }) } -
使用 adapter mock请求
-
import axios from "axios" const mockData = new Map([ ['/api/user/adapter/mock', { status: 200, statusText: 'OK', data: { message: '我是mock数据' } }] ]) export default function (config) { // 判断是否存在mock数据 let has = mockData.has(config.url) // 调用默认请求接口, 发送正常请求及返回 if (!has) { // 删除配置中的 adapter, 使用默认值 delete config.adapter // 通过配置发起请求 return axios(config) } return Promise.resolve(Object.assign({ headers: config.headers }, mockData.get(config.url))) } // axios.js import getAdapter from './axios-adapter'; const instance = axios.create({ // ... // 使用 adapter: getAdapter }); -
取消请求
-
可以分为三种情况:重复请求、用户手动取消、页面切换取消
-
重复请求
- Axios 如何取消重复请求?
-
jaimport Qs from 'qs' import axios from 'axios' const pendingRequest = new Map(); export function addPendingRequest(config) { const requestKey = generateReqKey(config); config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => { if (!pendingRequest.has(requestKey)) { pendingRequest.set(requestKey, cancel); } }); } export function removePendingRequest(config, src) { const requestKey = generateReqKey(config); if (pendingRequest.has(requestKey)) { const cancel = pendingRequest.get(requestKey); cancel(requestKey); pendingRequest.delete(requestKey); } } export function removePending(config) { const requestKey = generateReqKey(config); if (pendingRequest.has(requestKey)) { pendingRequest.delete(requestKey); } } function generateReqKey(config) { // 当请求方式、请求URL地址和请求参数都一样时,我们就可以认为请求是一样的 const { method = 'get', url, params, data } = config; // let data = typeof config.data === 'string' ? JSON.parse(config.data) : config.data return [method, url, Qs.stringify(params), Qs.stringify(data)].join("&"); } window.pendingRequest = pendingRequest
-
手动取消
-
let controller = null; <script> methods: { sendResponse() { // 传入给配置项 this.$http.user.getUser({}, {signal: controller.signal}) { } }, cancelResponse() { controller.abort() } } </script>
-
-
清空全部
-
window.pendingRequest.forEach((value,key) =>{ console.log(value(key)) }) window.pendingRequest = new Map() -
完整封装
-
import axios from 'axios' import { message as $Message } from 'ant-design-vue'; // 引自定义处理请求,这使测试更加容易(mock接口) import getAdapter from './axios-adapter'; // 添加请求响应拦截,处理重复请求。 import { addPendingRequest, removePendingRequest } from './axios-helper' // 引入方法 import { getToken, LogOut } from '@/utils/tools' // 引入日志处理 import { logInfo, redLog } from '@/utils/log' // 定义基础URL const baseURL = window.location.protocol + '' const instance = axios.create({ baseURL, timeout: 10000 * 5, headers: { Authorization: `xxxx ${getToken()}` }, adapter: getAdapter }); // 请求拦截器 const interceptorsRequest = config => { removePendingRequest(config, '请求') // 检查是否存在重复请求,若存在则取消已发的请求 addPendingRequest(config) // 把当前请求添加到pendingRequest对象中 return config } // 请求拦截器-错误处理 const interceptorsRequestFailed = error => { return Promise.reject(error) } // 响应拦截器 // 2xx 范围内的状态码都会触发该函数。 const interceptorsResponse = res => { removePendingRequest(res.config, '响应-成功'); // 从pendingRequest对象中移除请求 if (res.data.code === 200 || res.data.success) { // 添加http状态并返回 res.httpData = { status: res.status, statusText: res.statusText, } return res.data } else { let message = res.data.message || res.data.errorMessage // 响应状态码 switch (res.data.code) { case 404: break } $Message.destroy() $Message.error(message) return Promise.reject(message) } } // 响应拦截器-错误处理 // 超出 2xx 范围的状态码都会触发该函数。 const interceptorsResponseFailed = error => { removePendingRequest(error.config || {}, '响应失败'); // 从pendingRequest对象中移除请求 if (axios.isCancel(error)) { console.log('已取消重复请求: ' + error) } else { // HTTP 状态码 switch (error.status) { case 401: $Message.error('平台不可重复登录,请刷新页面重新登录') LogOut() case 500: error.message = '服务器错误(500)' break case 502: error.message = '网络错误(502)' } if (!window.navigator.onLine) { error.message = '请检查网络链接' } // 上传错误日志 logInfo(error) redLog(error) } return Promise.reject(error) } instance.interceptors.request.use(interceptorsRequest, interceptorsRequestFailed) instance.interceptors.response.use(interceptorsResponse, interceptorsResponseFailed) export default function request(e) { const { url = '', method = 'GET', data = {}, config = {}, option = {} } = e // 自定义配置项 // if (option) {} switch (method.toUpperCase()) { case 'GET': return instance.get(url, { params: data, ...config }) case 'POST': return instance.post(url, data, config) } }ja -
知识点
- Axios 响应拦截, HTTP状态码范围---默认范围
-
axios.interceptors.response.use(function (response) { // 2xx 范围内的状态码都会触发该函数。 // 对响应数据做点什么 return response; }, function (error) { // 超出 2xx 范围的状态码都会触发该函数。 // 对响应错误做点什么 return Promise.reject(error); );
-
- 使用config.validateStatus 定义了对于给定的 HTTP状态码是 resolve 还是 reject promise
-
{ validateStatus: function (status) { return status >= 200 && status < 300; // 默认值 } }
-
参考文档