三、撸vue/cli 3.+ 的正确姿势(axios插件、实现
2019-04-26 本文已影响572人
Baby_ed6e
1、为什么axios插件的封装
axios插件一般需要再次封装,比如设置header头,比如要设置统一的错误处理机制,总之包装一会让你开发更加便捷
2、新建一个request.js 并设置axios插件的config
import axios from "axios";
import qs from "qs"; // 一个序列化的插件,直接安装该插件即可(npm i qs)
import { message } from "ant-design-vue"; // 采用这ant-design-vue作为ui库,这里只是一个message提示工具,如果采用element ui 或者其他ui,对应使用提示组件就行了。
import store from "@/store/index"; // vuex,引入全局的状态
import baseURL from "./baseURL"; // 如第二章节讲的,根据不同环境提供了不同的打包地址
// 创建一个axios实例
const service = axios.create({
baseURL: baseURL,
timeout: 30000,
//`transformRequest`选项允许我们在请求发送到服务器之前对请求的数据做出一些改动,其作用是让参数(data)序列化
//该选项只适用于以下请求方式:`put/post/patch`
//数组里面的最后一个函数必须返回一个字符串、-一个`ArrayBuffer`或者`Stream`
// qs.stringify()将对象 序列化成URL的形式,以&进行拼接(需要qs在此转化为formdata,和api开发人员规定)
transformRequest: [
function(data) {
return qs.stringify(data);
}
],
//`paramsSerializer`是一个可选的函数,其作用是让参数(params)序列化
// 该选项只适用于以下请求方式:`get / delete `
paramsSerializer: function(params) {
return qs.stringify(params);
},
//`transformResponse`选项允许我们在数据传送到`then/catch`方法之前对数据进行改动
// 有些时候后台返回的response中真实数据在该对象下某个字段,例如 response.data,又或者是response本身,这里允许返回真实可利用的数据。
transformResponse: [
function(data) {
return data;
}
],
// 自定义loading参数,可在调用调用时候覆盖,也可以在拦截器里判断状态等。
// 这样我们可以轻松的定义是否需要在请求之前使用loading组件。
loading: true,
// 是否跨域,当然你也可以使用代理proxy 、nginx、
// 但是一般公司都不会每次都设置代理,而是使用固定的开发模式,例如直接做一个跨域的设置,一劳永逸
// 这里设置该属性还需要api开发者支持,设置后台的php程序里的header
withCredentials: true,
// 请求头,因为我们要使用formdata形式,所以设置如下
"Content-Type": "application/x-www-form-urlencoded"
// 如果采用json传递给后台数据,格式如下
// "Content-Type": "application/json;charset=utf-8"
});
3、设置拦截
import axios from "axios";
import qs from "qs";
import { message } from "ant-design-vue";
import store from "@/store/index";
import baseURL from "./baseURL";
const service = axios.create({
baseURL: baseURL,
timeout: 30000,
transformRequest: [
function(data) {
return qs.stringify(data);
}
],
paramsSerializer: function(params) {
return qs.stringify(params);
},
transformResponse: [
function(data) {
return data;
}
],
loading: true,
withCredentials: true,
"Content-Type": "application/x-www-form-urlencoded"
});
// 请求前
service.interceptors.request.use(
config => {
// 判断该次请求,是否需要loading,这里修改了一个全局状态。
// 这个loading是整个app层面的,暂且知道是可以调起整个页面loading的玩意儿
if (config.loading) {
store.dispatch("setLoading", true);
}
// 利用了一个函数,每次请求设置一个半小时后的时间放在,store和本地缓存里
// 再请求之前,如果该次请求距离上次请求超过半个小时,就清空store和本地缓存里的token
// 这样做的功能是,如果半小时后没操作请求,自动退出,一种安全机制,后续会详细解说,此处忽略即可,不影响封装的实现。
store.dispatch("CheckTokenExpiredTime");
// 设置header里的token
if (store.getters.token) {
config.headers["Authorization"] = "Bearer " + store.getters.token;
}
return config;
},
error => {
console.log(error);
Promise.reject(error);
}
);
// 请求后
service.interceptors.response.use(
response => {
// 服务器请求成功
// 修改loading状态
if (response.config.loading) {
store.dispatch("setLoading", false);
}
// 我们接口状态是在服务器请求200的情况下,再次返回自定义的状态码
// 服务器请求成功,也有可能会告诉少个参数等报错,此处允许我们自定义哪些报错抛出,哪些需要重新登录等(401,403)。
let data = JSON.parse(response.data);
if (data.ret_code === 200) {
return data.result;
} else {
if (data.ret_code === 403 || data.ret_code === 401) {
store.dispatch("setLoginDialog", true); // 一个弹出登录框的玩意儿
}
message.error(data.ret_msg); // 报错信息
return Promise.reject(data);
}
},
errorReponse => {
// 服务器请求错误
// 为了保持统一的错误处理,修改了浏览器报错的格式,与接口返回的失败格式一致
let response = errorReponse.response;
if (response.config.loading) {
store.dispatch("setLoading", false);
}
let errorJSON = {
ret_code: response.status,
ret_msg: errorReponse.message,
status: "Request Error",
result: errorReponse.response
};
if (errorJSON.ret_code === 403 || errorJSON.ret_code === 401) {
store.dispatch("setLoginDialog", true);
}
message.error(errorJSON.ret_msg);
return Promise.reject(errorJSON);
}
);
3、如何使用
在api目录下建立一个news.js文件,以下是增删改查的用法,任何一个模块的js都可以用如下写法
import request from "@/utils/request";
export default {
getList(params = {}) {
return request({
url: "admin/exams",
method: "get",
loading: false,
params: params // get请求,注意这里是params
});
},
detail(params = {}) {
return request({
url: "admin/exams/" + params.id,
method: "get",
params: {}
});
},
add(params = {}) {
return request({
url: "admin/exams",
method: "post",
data: params // 这里是data
});
},
update(params = {}) {
return request({
url: "admin/exams/" + params.exam_id,
method: "patch",
data: params
});
},
delete(params = {}) {
return request({
url: "admin/exams/" + params.id,
method: "delete",
data: {}
});
}
};
在.vue文件中如何使用api
import api from "@/api/articles";
export default {
data() {
return {
id: this.$route.params.id,
info: {}
};
},
created() {
this.getDetail();
},
methods: {
getDetail() {
api.detail({
id: this.id
}).then(res => {
this.info = res;
}).catch(err => {
console.log(err);
});
}
}
};
到这里就大功告成了,把所有的请求提取到api目录下的分模块的js文件中,通俗易懂,能够让界面清晰明了