本文为笔者实习期间学习记录
vue前端post/get封装与api接口统一管理
一、功能描述
采用原本使用axios的post/get与后端交互是这样的:
// 增加数据
add() {
this.$axios
.post("/add", {
requestHead: {
version: '1',
businessType: '1',
deviceId: '1',
deviceType: '1',
encryption: '1'
},
body: this.dictionary
})
.then(resp => {
// 成功增加数据后刷新页面
if (resp && resp.status === 200) {
this.$notify({
title: "成功",
message: "数据已成功插入",
type: "success",
duration: 1500
});
this.loadDictionaries();
this.dialogDictionary = false;
}
})
.catch(() => {
this.$message({
type: "error",
message: "数据插入失败",
duration: 1000
});
});
},
即,在需要与后端交互时,发出post/get请求,这样的情况下,url很分散,如果后端地址发生改变,前端就需要进行定位找到函数后再修改,很不方便. 另外一点是,由于发送的是自定义报文,请求头都是一样的,没必要每次请求都重复写. 所以将post/get方法以及自定义报文封装起来,api地址写在一个文件里统一管理,并且通过引用的方式在不同的vue文件里调用.
二、设计思路
-
Axios的封装
Axios是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中. 简单来说主要是用于向后台发起请求.
关于Axios,可以查看Axios中文文档.在src下的utils文件夹新建basedataRequest.js,用于封装Axios的post和get请求.
(1) 引入axios
// 在basedataRequest.js中引入axios import axios from 'axios'; // 引入axios
(2) 设置baseUrl和超时时间
通过axios.defaults.baseURL设置默认的基础地址,减少冗余.
通过axios.defaults.timeout设置默认的请求超时时间。例如超过了20s,就会告知用户当前请求超时,请刷新等.axios.defaults.timeout=50000; axios.defaults.baseURL="http://localhost/boss-bes-basedata-center/api/";
(3)请求拦截和响应拦截
axios里面可以设置拦截器 ,可以在我们正式请求发送之前做一些事情. 拦截器分请求拦截器和响应拦截器.
拦截器常见的用途是,对token的绑定进行统一的管理.
我们在前后端交互时使用token进行鉴权验证,首次请求后台返回token给前端,前端将token保存到本地,之后的每次发出的请求都需要带上这个token. 如果手动加上的话未免太过麻烦了,这时候就可以使用拦截器,在请求发出之前自动加上token信息.// request拦截器 service.interceptors.request.use(config => { //此处进行token等数据处理 return config }, error => { // 这里进行异常处理 Promise.reject(error) }); // respone拦截器 service.interceptors.response.use( response => { const res = response.data; if (res.code !== 200) { //此处进行异常处理 return Promise.reject(res); } return response }, error => { //此处进行异常处理 return Promise.reject(error) } );
(4)封装post和get方法
/** * 封装post请求 * @param url 请求地址 * @param data 请求参数 * @returns {Promise} 返回参数 */ export function post(url,data = {}){ return new Promise((resolve,reject) => { axios.post(url,data) .then(response => { resolve(response.data); },err => { reject(err) }) }) }
get方法类似
-
封装自定义报文
新建requestUtils.js文件.
头部为固定的公用数据.
将传入的参数作为body,加上头部requestHead的数据后返回./** * common request util * 从coookies 获取公共数据 * @param params * @returns {{head: {deviceType, crypt, businessType, version, deviceId, token}, body: *}} */ export function commonRequestUtil(params) { return { requestHead: { version: head.version, token: getToken(), businessType: head.businessType, deviceId: head.deviceId, deviceType: head.deviceType, crypt: head.crypt }, body: params } }
-
Api统一管理
新建index.js文件,引入上面的basedataRequest.js和requestUtils.js,export const loadDictionaryIdAndValueList=p =>post('/Dictionary/getDictionaryListByName',commonRequestUtil(p));
上面定义了一个loadDictionaryIdAndValueList方法,这个方法有一个参数p,p是我们请求接口时携带的参数对象。而后调用了之前封装的post方法,post方法的第一个参数是请求地址url,第二个参数是进行报文封装后body为p的参数,最后通过export导出该方法使得其他文件可以引用.
三、代码实现
- index.js
import request from '../utils/basedataRequest';
import { post, put, deletes, get } from '../utils/basedataRequest'
import {commonRequestUtil} from '../utils/requestUtils'
export const fetchData = (query) => {
return request({
url: '/ms/table/list',
method: 'post',
data: query
})
}
/*深拷贝,复制一份数据解除双向绑定,使dialog数据改变时row的数据不变*/
export const deepClone=obj=>{
let _obj = JSON.stringify(obj),
objClone = JSON.parse(_obj);
return objClone
}
/*api接口统一管理 */
//---------------------数据字典api------------------------//
export const loadDictionaryIdAndValueList=p=>post('/Dictionary/getDictionaryListByName',commonRequestUtil(p));
export const queryDictionary=p=>post('/Dictionary/query',commonRequestUtil(p));
export const addDictionary=p=>post('/Dictionary/add',commonRequestUtil(p));
export const deleteDictionaries=p=>post('/Dictionary/delete',commonRequestUtil(p));
export const updateDictionary=p=>post('/Dictionary/update',commonRequestUtil(p));
- basedataRequest.js
import axios from 'axios';
import {Loading}from 'element-ui' //****在这里引入Loading组件****
axios.defaults.timeout=50000;
axios.defaults.baseURL="http://localhost/boss-bes-basedata-center/api/";
//request拦截器
service.interceptors.request.use( config => {
//请求前到请求到数据这段时间用加载动画来代替,以服务方式调用
// let loading = Loading.service({
// fullscreen: true,
// text: '拼命加载中...',
// });
return config;
}, error => {
console.log(error);
// let loading = Loading.service({});
// loading.close();
return Promise.reject();
})
//response拦截器
service.interceptors.response.use(response => {
// let loading = Loading.service({});
// loading.close();
if(response.status === 200){
return response.data;
}else{
Promise.reject();
}
}, error => {
console.log(error);
return Promise.reject();
})
/**
* 封装get方法
* @param url
* @param data
* @returns {Promise}
*/
export function fetch(url,params={}){
return new Promise((resolve,reject) => {
axios.get(url,{
params:params
})
.then(response => {
resolve(response.data);
})
.catch(err => {
reject(err)
})
})
}
/**
* 封装post请求
* @param url
* @param data
* @returns {Promise}
*/
export function post(url,data = {}){
return new Promise((resolve,reject) => {
axios.post(url,data)
.then(response => {
resolve(response.data);
},err => {
reject(err)
})
})
}
/**
* 封装put请求
* @param url
* @param data
* @returns {Promise}
*/
export function put(url,data = {}){
return new Promise((resolve,reject) => {
axios.put(url,data)
.then(response => {
resolve(response.data);
},err => {
reject(err)
})
})
}
- 在vue文件中使用
使用import从index.js引入要使用的方法,然后可在本地方法中直接使用,参数为body部分,无需再写出头部以及url信息.
<script>
import {
loadDictionaries,
addDictionary,
updateDictionary,
deleteDictionaries,
queryDictionary,
deepClone
} from "../../api/index";
export default {
methods: {
// 增加数据
add() {
this.$refs.Dictionary.validate((valid) => {
if (valid) {
addDictionary(this.dictionary)
.then(resp => {
// 成功增加数据后刷新页面
if (resp && resp.responseHead.code === "0") {
this.$notify({
title: "成功",
message: "数据已成功插入",
type: "success",
duration: 1500
});
this.loadDictionaries();
this.dialogDictionary = false;
} else if (resp) {
this.$notify({
title: "失败",
message: "错误码:" + resp.responseHead.code + " 错误信息:" + resp.responseHead.message,
type: "error",
duration: 1500
});
}
})
.catch(() => {
this.$message({
type: "error",
message: "数据插入失败",
duration: 1500
});
});
}
});
},
</script>