优点
- 统一维护管理接口;
- 支持接口代理转发;
- 读取环境配置,区分处理环境。
- 拦截请求和响应,处理登录超时、404 等异常情况;
- 根据请求的配置匹配接口 URL 前缀且作支持做特殊处理。
封装
安装 axios
npm install axios;
创建实例
通过创建实例,操作实例的方式进行接口请求。
//request.js import axios from 'axios'; // 引入axios import Qs from 'qs'; // 引入qs模块,用来序列化post类型的数据 import { autoMatch, checkStatus } from './utils'; // 处理函数 import { Toast } from 'mint-ui'; //提示框 // 创建axios实例 const instance = axios.create({ // baseURL: process.env.BASE_URL, timeout: 30000, // 请求超时时间 // `transformRequest` 允许在向服务器发送前,修改请求数据 transformRequest: [function (data) { // 对 data 进行任意转换处理 return data; }], // `transformResponse` 在传递给 then/catch 前,允许修改响应数据 transformResponse: [function (data) { // 对 data 进行任意转换处理 return JSON.parse(data); }] })
添加请求和响应拦截器
给实例添加请求和响应拦截器,根据实际数据格式进行相应的处理。
比如:
请求时,应后端要求根据 Content-type 设置 data 传参格式;
响应时,统一处理登录超时的情况和请求失败的错误提示处理等。
//request.js // 实例添加请求拦截器 instance.interceptors.request.use(function (config) { // 在发送请求之前做处理... config.headers = Object.assign(config.method === 'get' ? { 'Accept': 'application/json', 'Content-Type': 'application/json; charset=UTF-8' } : { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, config.headers); if (config.method === 'post') { const contentType = config.headers['Content-Type']; // 根据Content-Type转换data格式 if (contentType) { if (contentType.includes('multipart')) { // 类型 'multipart/form-data;' // config.data = data; } else if (contentType.includes('json')) { // 类型 'application/json;' // 服务器收到的raw body(原始数据) "{name:"nowThen",age:"18"}"(普通字符串) config.data = JSON.stringify(config.data); } else { // 类型 'application/x-www-form-urlencoded;' // 服务器收到的raw body(原始数据) name=nowThen&age=18 config.data = Qs.stringify(config.data); } } } return Promise.resolve(config); }, function (error) { // 对请求错误做处理... return Promise.reject(error); }); // 实例添加响应拦截器 instance.interceptors.response.use(function (response) { // 对响应数据做处理,以下根据实际数据结构改动!!... // const { reason_code } = response.data || {}; // if (reason_code === '001') { // 请求超时,跳转登录页 // const instance = Toast('请求超时,即将跳转到登录页面...'); // setTimeout(() => { // instance.close(); // window.location.href = '/login'; // }, 3000) // } return Promise.resolve(checkStatus(response)); }, function (error) { // 对响应错误做处理... return Promise.reject(checkStatus(error.response)); });
处理错误状态:
//utils.js export function checkStatus (response) { const status = response.status || -1000; // -1000 自己定义,连接错误的status if ((status >= 200 && status < 300) || status === 304) { // 如果http状态码正常,则直接返回数据 return response.data; } else { let errorInfo = ''; switch (status) { case -1: errorInfo = '远程服务响应失败,请稍后重试'; break; case 400: errorInfo = '400:错误请求'; break; case 401: errorInfo = '401:访问令牌无效或已过期'; break; case 403: errorInfo = '403:拒绝访问'; break; case 404: errorInfo = '404:资源不存在'; break; case 405: errorInfo = '405:请求方法未允许' break; case 408: errorInfo = '408:请求超时' break; case 500: errorInfo = '500:访问服务失败'; break; case 501: errorInfo = '501:未实现'; break; case 502: errorInfo = '502:无效网关'; break; case 503: errorInfo = '503:服务不可用' break; default: errorInfo = `连接错误` } return { status, msg: errorInfo } } }
封装实例
实例封装到 async\await 异步函数中。
//request.js const request = async function (opt) { try { const options = Object.assign({ method: 'get', ifHandleError: true // 是否统一处理接口失败(提示) }, opt); // 匹配接口前缀 开发环境则通过proxy配置转发请求; 生产环境根据实际配置 options.baseURL = autoMatch(options.prefix); const res = await instance(options); // console.log(res); if (!opt.ifHandleError) { // 自定义参数,是否允许全局提示错误信息 Toast(res.error || '请求处理失败!') } return res; } catch (err) { if (!opt.ifHandleError) { // 自定义参数,是否允许全局提示错误信息 Toast(err.msg || '请求处理失败!') } return err; } }
- 此处可以增加对请求入参进行合并或默认值处理;
- 自定义参数配置
项目中统一处理报错提示。但有时对于接口请求比较多的情况,很多时候并不希望某些接口被全局报错提示。这时这种接口可以设置自定义的 ifHandleError 参数处理,不进行全局错误提示,而是到业务代码中再做处理。
同理,其他的一些特殊业务情况也可以通过自定义参数处理。
- 根据自定义的 prefix 参数匹配接口前缀;
对于项目中请求多个后端的接口时,每个接口在请求封装时附带 prefix 参数,根据 prefix 的值 autoMatch函数
统一处理,自动匹配接口前缀。
- 开发环境可通过 webpack proxy 配置转发请求。
- 生产环境读取实际配置(根据实际项目的情况)。
autoMath 方法:
// utils.js const isDev = process.env.NODE_ENV === 'development'; // 开发 or 生产 // 匹配接口前缀 export function autoMatch (prefix) { let baseUrl = ''; if (isDev) { // 开发环境 通过proxy配置转发请求; baseUrl = `/${prefix || 'default'}`; } else { // 生产环境 根据实际配置 根据 prefix 匹配url; // 配置来源 根据实际应用场景更改配置。(1.从全局读取;2.线上配置中心读取) switch (prefix) { case 'baidu': baseUrl = window.LOCAL_CONFIG.baidu; break; case 'alipay': baseUrl = window.LOCAL_CONFIG.alipay; break; default: baseUrl = window.LOCAL_CONFIG.default; } } return baseUrl; }
开发环境接口代理
webpack 配置,比如:@vue/CLI3 在 vue.config.js
中配置:
devServer: { proxy: { '/baidu': { target: 'http://10.59.81.31:8088', changeOrigin: true, pathRewrite: { '^/baidu': '' } }, '/default': { target: 'http://10.59.81.31:8088', changeOrigin: true, pathRewrite: {'^/default' : ''} }, } },
统一配置接口
在一个新文件 apiUrl.js
中统一管理项目全部的接口,方便维护。
//apiUrl.js export const apiUrl = { login: '/api/login', loginOut: '/api/loginOut', qryPageConfig: '/test/qryPageConfig', setPageConfig: '/test/setPageConfig', //... }
生成接口
在 index.js
中:
import Vue from 'vue'; import request from './request'; import { apiUrl } from './apiUrl'; let services = {}; Object.entries(apiUrl).forEach((item) => { services[item[0]] = function (options = {}) { return request(Object.assign({ url: item[1] }, options)) } }) // 将services挂载到vue的原型上 // 业务中引用的方法:this.$services.接口名(小驼峰) Object.defineProperty(Vue.prototype, '$services', { value: services }); export default services;
在上述代码中,通过读取配置的接口信息 (名称和请求路径),生成全部接口。 并挂载到 vue 的原型上,这样在业务中就可以通过 this.$services.接口名
直接调用对应的接口。
当然,这是本项目使用的方法。 因具体项目而异,也可以不挂载到 Vue 原型上,使用 services 模块;或直接调用 request.js
封装的请求函数。
业务调用
以下为使用事例:
// index.vue methods中 methods: { // 获取页面配置信息接口 get Promise $_qryPageConfig() { this.$services.qryPageConfig({ method: 'get', //默认 params: { page: 'login' }, }).then((res) => { this.pageConfig = res.data; }).finally(() => { ... this.close(); }); }, // 设置页面配置接口 post async/await $_order: async function () { this.loading = true; const res = await this.$services.setPageConfig({ prefix: 'baidu', //匹配url前缀 ifHandleError: true, //不对该接口进行全局错误提示。 method: 'post', headers: { 'Content-Type': 'application/json; charset=UTF-8', }, data: { userId: this.idCard, userName: this.realName, color: 'red', } }) this.loading = false; if (res.data) { Total('success'); } }, }
项目代码
项目代码本身依附于 @vue/CLI3 构建,是 CLI3 构建移动 H5 端应用的一部分。当然通过剥离 vue 代码,该 Axios 封装也可以直接应用到其他项目中。
项目源码:
@vue/CLI3 构建移动 H5 端应用:juejin.im/post/5d674d…;
Github 链接:github.com/now1then/vu…;
来源:https://www.cnblogs.com/bj904186281/p/12093105.html