目录
- 前言
- 目的
- 文件结构
- 实现
- 请求拦截
- 响应拦截
- 取消重复发送请求
- 调用
- 总结
前言
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
axios 是目前最优秀的 HTTP 请求库之一, 我们封装 axios 请求也是为了让代码看的更加清晰, 后期好维护.
目的
- 实现请求拦截
- 实现响应拦截
- 常见错误处理
- 不能请求头设置
- api 集中式管理
(取消重复请求,重复发送请求, 请求缓存等情况均还未实现)
文件结构
实现
index.js内代码如下:
引入
// 引入 axios | |
import axios from 'axios'; | |
// 请求配置单独写一个文件 baseurl.js | |
import serverConfig from './baseurl.js' |
创建一个实例
const serviceAxios = axios.creat({ | |
baseURL: serverConfig.baseURL, //基础请求地址 | |
timeout: 1000 , //请求超时设置 | |
withCredentials: false, // 跨域请求是否需要携带 cookie | |
}) |
请求拦截
serviceAxios.interceptors.request.use( | |
(config) => { | |
console.log("请求配置", config); | |
// 是否使用 Token, | |
if(serverConfig.useTokenAuthorization) { | |
config.headers["Authorization"] = localStorage.getItem("token"); | |
} | |
// 设置请求头 | |
if(config.method === "post") { | |
config.headers["content-type"] = "application/x-ww-form-urlencoded"; | |
// config.data = qs.stringify(config.data); //序列化 效果等同于下行代码 | |
config.requestType = "form" | |
} else { | |
config.headers["content-type"] = "application/json" | |
} | |
// 返回 | |
return config | |
}, | |
(error) => { | |
Promise.reject(error) | |
} | |
) |
响应拦截
serviceAxios.interceptors.response.use( | |
(res) => { | |
console.log("响应拦截", res); | |
let data = res.data; | |
// 处理自己的业务逻辑,如 token 是否过期... | |
return data; | |
}, | |
(error) => { | |
let message = "" | |
if(error && error.response) { | |
switch (error.response.status) { | |
case 302: | |
message = "接口重定向了! "; | |
break; | |
case 400: | |
message = "参数不正确! "; | |
break; | |
case 401: | |
message = "您未登录, 或者登录已经超时, 请先登录! " | |
break; | |
case 403: | |
message = "您还没有权限操作! "; | |
break; | |
case 404: | |
message = `请求地址出错: ${error.response.config.url}`; | |
break; | |
case 408: | |
message = "请求超时! "; | |
break; | |
case 409: | |
message = "系统已存在相同数据! " | |
break; | |
case 500: | |
message = "服务器内部错误! " | |
break; | |
case 501: | |
message = "服务未实现! " | |
break; | |
case 502: | |
message = "回答错误! " | |
break; | |
case 503: | |
message = "服务不可用" | |
break; | |
case 504: | |
message = "服务暂时无法访问, 请稍后再试" | |
break; | |
case 505: | |
message = "HTTP 版本不受支持! " | |
break; | |
default: | |
message = "异常问题, 请联系管理员! " | |
break; | |
} | |
} | |
return Promise.reject(message); | |
} | |
); |
取消重复发送请求
实现思想
唯一标识值 : 每次发起请求的时候根据请求的方式,请求URL,请求携带参数设置一个唯一标识值.
请求队列: 创建一个map对象储存请求的唯一标识值.
每次发送请求的时候, 在请求拦截中判断请求队列中是否存在这个请求, 存在就说明这个请求正在进行中,那么就取消正在发送的请求,重新发送请求; 不存在就将本次请求加入请求队列中.
在响应拦截中将本次请求从请求队列中移除.
📘生成唯一标识值函数
import qs from 'qs' | |
function regsoleKey(config){ | |
const {method, url, params, data } = config; | |
return [method, url, qs.stringify(params), qs.stringify(data)].join('&') | |
} |
📘将请求加入请求队列函数
const reqQueue = new Map(); | |
function addreqQueue(config){ | |
//调用生成唯一标识值函数, 生成 requestKey | |
const requestKey = regsoleKey(config); | |
//为每个请求创建一个专属的 CancelToken(用于取消请求) | |
config.cancelToken = config.cancelToken || new axios.CancelToken((cancel)=>{ | |
// 判断 reqQueue 中是否含有 requestKey, | |
// 将 requestKey 与 CancelToken 以键值对的形式保存到map对象中 | |
if(!reqQueue.has(requestKey)){ | |
reqQueue.set(requestKey,cancel) | |
} | |
}); | |
} |
📘将请求从请求队列移除
function removereqQueue(config){ | |
// 标识值 | |
const requestKey = generateReqKey(config); | |
if(reqQueue.has(requestKey)){ | |
// 取消之前发出请求 | |
const cancelToken = reqQueue.get(requestKey); | |
cancelToken(requestKey); | |
// 从队列移除 | |
reqQueue.delete(requestKey); | |
} | |
} |
💧请求拦截器
serviceAxios.interceptors.request.use( | |
function(config) { | |
removereqQueue(config); // 检查是否重复发送请求 | |
addreqQueue(config); //将本次请求加入请求队列 | |
return config | |
}, | |
(error) => { | |
return Promise.reject(error) | |
} | |
) |
💧响应拦截器
serviceAxios.interceptors.response.use( | |
(res) => { | |
removereqQueue(res.config); //请求从请求队列移除 | |
return res | |
}, | |
(error) => { | |
removereqQueue(error.config || {}); //请求从请求队列移除 | |
//.... | |
} | |
) | |
// 最后 | |
export default serviceAxios |
baseurl.js代码如下
const serverConfig = { | |
baseURL: 'https://fm-emo-music-api.vercel.app', | |
useTokenAuthorization: true, //是否开启 token 验证 | |
} | |
export default serverConfig |
api.js代码如下
// 引入index.js | |
import serviceAxios from './index.js' | |
// get实例 | |
export const VideoRecommendLike = (params) => { | |
return serviceAxios({ | |
method: "get", | |
url: "/dj/personalize/recommend", | |
params, | |
}) | |
} | |
// post实例 | |
export const ConfirmPhone = (data) =>{ | |
return serviceAxios({ | |
method: "post", | |
url: "/captcha/sent", | |
data, | |
}) | |
} |
调用
如何在原生js文件内调用?
首先引入axios文件
<!-- axios请求文件 --> | |
<script src="/src/utils/axios.js"></script> |
再引入带有axios请求的js文件, 请求文件内使用es6新语法按需引入api.js文件
例:
import {useRouter} from '../../router/app.js'
如何在Vue文件内使用?
示例:
// 按需引入请求接口 | |
import {emailCounts} from "@/api/api.js" | |
export default { | |
... | |
// 异步进行axios请求 | |
methods: { | |
async comein(){ | |
let res = await emailCount(params) | |
console.log(res) | |
} | |
} | |
} |