简易封装
在介绍如何封装axios之前,请大家先了解一下我们之后将要创建的三个文件及其含义,为后续理解代码做准备
三个主要文件:
status.js 保存状态码以及对应默认返回信息
interceptor.js 定义axios拦截器与初始url
http.js 封装GET POST请求
api-xxx.js 专门用于处理某项请求的API接口
以上四个文件在接下来的演示中都在同一个文件夹下!
status.js
在这里简单的定义几个装填码,后续我们会直接调用他们
代码清单 status.js
// 在这里存储所有状态码及其对应的所有信息
export const STATUS = {
success: {
id: 200,
msg: "请求成功",
},
failed: {
id: 400,
msg: "请求失败",
},
};
interceptor.js
这里需要安装三个库:axios、qs、element-plus
该拦截器包含了以下功能:
前端请求后端时自动从自身的localstorage中提取token,放置于请求头中发送给后端;
可以对GET请求的参数进行字符串化;
可以拦截响应体,并判断token是否过期而让用户重新登陆(重定向到登录页面);
代码清单:interceptor.js
import axios from "axios";
import qs from "qs";
import { ElMessage } from "element-plus";
import { STATUS } from "./status";
// 初始化后端服务器数据
const server = axios.create({
baseURL: "http://localhost:10001",
timeout: 30 * 1000,
});
// 请求拦截器
server.interceptors.request.use(
(config) => {
// 如果请求方法为GET,则字符串化params
if (config.method === "get") {
config.paramsSerializer = (params) => {
return qs.stringify(params, {
arrayFormat: "comma",
});
};
}
// 获取用户token并附带在headers里传递给后端
const token = localStorage.token;
if (token) {
config.headers["token"] = token;
}
return config;
},
(err) => {
Promise.reject(err);
}
);
// 响应拦截器
server.interceptors.response.use(
// 如果没错误就直接通过不拦截
(config) => {
return config;
},
(err) => {
// 如果错误的响应体存在的话
if (err.response) {
// 获取响应值message
const msg =
err.response.data === null
? "服务端出错,无法获取响应内容"
: err.response.data.message;
// 根据响应状态码来返回对应信息
switch (err.response.status) {
case STATUS.success.id:
ElMessage(STATUS.success.msg);
break;
default:
// 后端验证token无效,写到响应体里返回给前端
// 前端在此判定为无效,提示对应信息
if (msg === "invalid_token") {
ElMessage("token无效,请重新登陆");
} else {
ElMessage(msg);
}
break;
}
}
return Promise.reject(err);
}
);
// 导出拦截器供后续使用
export default server;
http.js
主要对 get 和 post 方法进行封装,设置 config,并判断有无 params 以及 formdata 来决定是否添加对应参数到请求体中
特别的,对于 post 请求的 config,必须要设置 header
中的 content-type
,否则后端无法识别传递过来的 formdata(比如 GIN 框架下就是无法识别的!)
代码清单:http.js
import qs from "qs";
import intcp from "./interceptor";
const http = {
// axios执行get请求
get(url, params) {
const config = {
method: "get",
url: url,
};
// 当存在params时,才会将其添加到config并发送给后端
if (params) config.params = params;
return intcp(config);
},
// axios执行post请求
post(url, formdata) {
const config = {
method: "post",
url: url,
// 这一条必须要加,否则后端无法识别formdata
headers: {
"Content-type": "application/x-www-form-urlencoded",
},
};
if (formdata) config.data = formdata;
console.log(config);
return intcp(config);
},
};
export default http;
API接口文件
下面仅展示前端接口文件书写,后端内容不是关键点,这里略过
这里我们编写一个用户CRUD接口,文件名为 api-modify.js
这里只是简单调用http进行二次封装,最终promise请求还需要在主代码中处理
为什么不直接在api中处理前后端交互逻辑的原因是:很多情况下我们会用到后端发回来的响应体中的值,写在主代码中可以直接获取它并变成响应式, 而直接在api里面写就会涉及到作用域以及数据传递问题,极不方便!!!
import http from "./http.js";
// 随意订制三个接口,明确各自的请求方法
export default {
selectUserList: (url) => {
return http.get(url)
},
insertUser: (url, data) => {
return http.post(url, data)
},
deleteUser: (url, data) => {
return http.post(url, data)
}
}
主代码
所谓主代码,即调用api接口的代码,在这里需要对api的promise进行then和catch,并针对性的做出响应
下方代码演示了,使用pinia配合api,获取后端值并存储的完整流程
import {onMounted, reactive, ref} from "vue";
import apiQuery from "../../api/api-query.js";
import dbStore from "../../store/db-store.js";
// 实例化store
const store = dbStore()
// 动态绑定store中数据,以便其一发生改变(前端取回后端返回数据),立即可得到渲染更新
let datas = reactive(store.$state.userLists)
// api接口,需自行处理then以及catch逻辑!
apiQuery.userDataQuery("/sdb/allusers").then(res => {
store.setUsersList(res)
console.log(res[0], "fuck")
})