Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
vue接口数据请求一般都使用的axios,先来看一下axios的部分常用配置项:
// `url` 是用于请求的服务器 URL
url: '/user',
// `method` 是创建请求时使用的方法
method: 'get', // default
// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
baseURL: 'https://some-domain.com/api/',
// `transformRequest` 允许在向服务器发送前,修改请求数据
// 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
// 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
transformRequest: [function (data, headers) {
// 对 data 进行任意转换处理
return data;
}],
// `transformResponse` 在传递给 then/catch 前,允许修改响应数据
transformResponse: [function (data) {
// 对 data 进行任意转换处理
return data;
}],
// `headers` 是即将被发送的自定义请求头
headers: {'X-Requested-With': 'XMLHttpRequest'},
// `params` 是即将与请求一起发送的 URL 参数
// 必须是一个无格式对象(plain object)或 URLSearchParams 对象
params: {
ID: 12345
},
// `paramsSerializer` 是一个负责 `params` 序列化的函数
// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function(params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})
},
// `data` 是作为请求主体被发送的数据
// 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
// 在没有设置 `transformRequest` 时,必须是以下类型之一:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 浏览器专属:FormData, File, Blob
// - Node 专属: Stream
data: {
firstName: 'Fred'
},
// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
// 如果请求话费了超过 `timeout` 的时间,请求将被中断
timeout: 1000,
拦截器
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
如果你想在稍后移除拦截器,可以这样:
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
可以为自定义 axios 实例添加拦截器
const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
上面所列只是部分请求配置项,也是最常用的,想要更多了解可以看axios官网,很详细。
项目中使用主要是对axios进行封装,以便后续使用,所以这里主要分享下项目封装的axios方法。
第一种:
import axios from 'axios'
import { Message, MessageBox } from 'element-ui' // 弹窗组件
import store from '@/store' // 状态管理
import { getToken } from '@/utils/auth' // 获取cookie
import qs from 'qs'
// create an axios instance
// 新建一个 axios 实例
const service = axios.create({
baseURL: process.env.BASE_API, // api的base_url
timeout: 100000 // request timeout
})
// 发送请求前对请求数据进行处理
service.defaults.transformRequest = [function(data) {
/**
* axios默认请求Context-type是application/json,也就是默认发送json格式参数,后台需要用@RequestBody进行处理
* 这里统一用qs对请求参数进行格式化成FormData格式
*/
return qs.stringify(data)
}]
// 请求拦截器
service.interceptors.request.use(config => {
// Do something before request is sent
// 配置 如果是首页导出 超时时间设置为5min(下面的path是请求的url,这是之前的写法)
// if (config.url === '/homePageStatis/entireSuperviseExcel' || config.url === '/homePageStatis/alarmHandleInfoExcel' || config.url === '/homePageStatis/callAlarmAccidentExcel' || config.url === '/homePageStatis/callAlarmViolationExcel') {
// config.timeout = 1000 * 60 * 5
// }
// 导出时 超时时间设为5min
if (config.responseType === 'blob') {
config.timeout = 1000 * 60 * 5
}
if (store.getters.token) {
// 让每个请求携带token-- ['XN-Auth']为自定义Header key
config.headers['XN-Auth'] = getToken()
}
return config
}, error => {
// Do something with request error
Promise.reject(error)
})
// 响应拦截器
service.interceptors.response.use(
/* response => {
return response.data
}, */
/**
* 通过在response里自定义code来标示请求状态,这里根据不同的code情况做相应的处理<br>
* 也可以通过XMLHttpRequest对象状态码标识进行相应的处理
*/
response => {
const res = response.data
// alert(JSON.stringify(response.data))
if (res.code !== 0) {
// 1004:Token 过期了
if (res.code === 1004) {
// 请自行在引入 MessageBox
MessageBox.confirm('您已退出系统,可以继续留在该页面,或者重新登录', '确定登出', {
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
store.dispatch('FedLogOut').then(() => {
location.reload() // 为了重新实例化vue-router对象 避免bug
})
}).catch(() => {
})
// 统一处理系统异常,不再发给上层业务(在这里统一处理后就不需要在单个组件中处理)
} else if (res.code === 1001 || res.code === 1002 || res.code === 1003 || res.code === 1005 || res.code === 1006 || res.code === 1007 || res.code === 1008 || res.code === 1009 || res.code === 1010 || res.code === 2011) {
Message({
message: res.msg,
type: 'info',
duration: 1 * 1000
})
} else { // 对其它返回状态码是非0的情况,这里捕获并返回reject的Promise对象,上层业务通过catch处理异常信息
return Promise.reject(res)
}
} else {
return res
}
},
error => { // 对XMLHttpRequest状态码非200的处理
console.log('err:' + JSON.stringify(error)) // for debug
Message({
message: error.message,
type: 'info',
duration: 3 * 1000
})
return Promise.reject(error)
})
export default service
这里还算是比较详细了,相信大家应该都能看的懂~~
封装是这样封装了,那么怎么调用呢? 直接传入配置项即可
// 项目中同一模块下的接口是可以统一管理的,新建一个文件夹
// 引入axios
import request from '@/utils/request'
// get方法(prodata为形参,名字随便起)
export function carlist(prodata) {
return request({
url: '/base/vehicle',
method: 'get',
params: prodata
})
}
// post方法(data即 data: data)
export function addMsg(data) {
return request({
url: '/alarm/record/contentModle',
method: 'post',
data
})
}
// put方法
export function driverStatus(params) {
return request({
url: `/event/${params.id}?status=${params.status}`,
method: 'put'
})
}
// delete方法
export function deleteMsg(id) {
return request({
url: `/alarm/record/contentModle/${id}`,
method: 'delete'
})
}
页面调用直接引入定义调用方法的文件,直接在页面使用即可。
第二种:
import axios from "axios";
import { Message } from "element-ui";
import { Loading } from "element-ui";
import store from "@/store";
import qs from "qs";
const operator = (function () { // 服务方式创建一个加载中的loading,引用elementUI的组件
let loadingInstance = null;
return {
QUERY_ERROR: "数据有误",
hasLoading: true,
loading(flag) {
this.hasLoading = flag;
if (this.hasLoading) {
loadingInstance = Loading.service({
lock: true,
fullscreen: true,
text: "Loading",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.5)"
});
}
},
close() {
loadingInstance && loadingInstance.close();
}
};
})();
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
// timeout: 50000,
proxy: {}
});
// 发送请求前对请求数据进行处理
// service.defaults.transformRequest = [
// function(data) {
// /**
// * axios默认请求Context-type是application/json,也就是默认发送json格式参数,后台需要用@RequestBody进行处理
// * 这里统一用qs对请求参数进行格式化成FormData格式
// */
// return qs.stringify(data); // 用qs将对象转换成拼接的字符串
// }
// ];
// request 拦截
service.interceptors.request.use(
config => {
// console.log(store.getters.authorizationToken);
config.headers = {
"Content-Type": "application/x-www-form-urlencoded",
// "Content-Type": "application/json",
Authorization: `Bearer ${store.getters.authorizationToken}`
//'token':localStorage.getItem('token')
};
operator.loading(config.hasLoad);
// if (config.method == "post") {
// config.params = {};
// }
return config;
},
error => {
// operator.close();
Promise.reject(error);
}
);
// respone 拦截
service.interceptors.response.use(
response => {
// let res = response.data;
if (response.status === 200) {
let data = response.data;
let total = 0;
// 由于后台框架的原因,请求响应数据中没有返回列表的数据总数,而是在响应头中以x-total-count
// 的字段形式体现,所以在这里做一下修改
if (response.headers["x-total-count"]) {
total = response.headers["x-total-count"];
}
// if (data) {
// Object.prototype.toString.apply(data.total);
// if (Object.prototype.toString.apply(data.total) === "[object Number]") {
// data["pagination"] = {
// pageNum: data.pageNum, //当前页数
// pageSize: data.pageSize, //显示数量
// total: data.total,
// pageCount: data.pages
// };
// }
// }
resStatus();
// 因为请求响应数据中没有data字段,所以在这里添加
return { data: data, total: total };
} else {
resStatus();
}
function resStatus() {
setTimeout(() => {
operator.close();
}, 200);
}
},
error => {
var reg = RegExp(/404/);
if (reg.test(error.message)) {
$request.status = {
errorMessage: error.message,
errorType: error.request.status
};
// window.location.href = 'http://localhost:8080/#/error404'
}
Message({
message: error.message,
type: "error"
});
operator.close();
return Promise.reject(error);
}
);
// get post put delete方法封装
const $request = {
get: function (url, params, load) {
let hasLoad = false;
if (typeof Array.prototype.pop.apply(arguments) === "boolean") {
hasLoad = load;
}
return service({
url: url,
method: "get",
params: params,
hasLoad: hasLoad
});
},
post: function (url, params, load) {
let hasLoad = false;
if (typeof Array.prototype.pop.apply(arguments) === "boolean") {
hasLoad = load;
}
return service({
url: url,
method: "post",
params: params,
// data: params,
hasLoad: hasLoad
});
},
delete: function (url, params, load) {
let hasLoad = false;
if (typeof Array.prototype.pop.apply(arguments) === "boolean") {
hasLoad = load;
}
return service({
url: url,
method: "delete",
params: params,
hasLoad: hasLoad
});
},
put: function (url, params, load) {
let hasLoad = false;
if (typeof Array.prototype.pop.apply(arguments) === "boolean") {
hasLoad = load;
}
return service({
url: url,
method: "put",
params: params,
hasLoad: hasLoad
});
},
axios: service,
status: ""
};
export default $request;
调用:
import $http from '@/utils/request'
// 调用方法如同这种方式,切换方法只是更换方法明便可,如get、post等
// 这里创建了一个promise对象返回请求结果
queryTableData = params => {
return new Promise((resolve, reject) => {
let url = "/api/vehicle/areaNetworkStatistics";
this.$https.get(url, params).then(response => {
resolve(response);
});
});
};
页面调用方法同上。
第三种:
/* eslint-disable */
import axios from 'axios'; // 引入axios
import QS from 'qs'; // 引入qs模块,用来序列化post类型的数据,后面会提到
import Vue from 'vue';
import store from '@/store';
import router from '@/router';
let ipcRenderer = window.ipcRenderer;
import cookie from '@/router/cookies'
const pc = axios.create({
timeout: 20000,
baseURL: process.env.VUE_APP_API
});
//HttpRequest拦截器
pc.interceptors.request.use(
async (config) => {
// 获取token
let result = await new Promise((resolve, reject) => {
//获取用户TOKEN 信息
var realToken = localStorage.getItem("pcToken");
if (realToken) {
config.headers.authorization = `Bearer ${realToken}`
}
resolve(config);
});
return result;
// config.headers.authorization = `Bearer d3480236-c501-45ea-b3c2-5f540b806660`
// return config
},
(err) => {
return Promise.reject(err);
}
);
//HttpResponse拦截器
pc.interceptors.response.use(
(response) => {
console.log("执行了HttpResponse")
if (response.data.code == 1 || (response.data.code == 500 && response.data.msg && response.data.msg == '身份验证失败')) {
//假如用户登录过期,则提示用户登录对话框
let msg = Vue.prototype;
//假如用户登录过期,则提示用户登录对话框
if (store.state.isTrue) {
store.commit('SET_ISTRUE', false)
msg.$alert('当前用户登录信息过期了,请重新登录', '温馨提示', {
confirmButtonText: '确定',
callback: action => {
localStorage.setItem('isFailure', true)
store.dispatch("logout");
cookie.cookieClear("token")
localStorage.removeItem("autoLogo");
localStorage.removeItem("pcToken");
localStorage.removeItem("token");
localStorage.removeItem("resData");
ipcRenderer.send("resetWinSize");
router.push("/");
}
});
} else {
return response;
}
}
return response;
},
(error) => {
return Promise.reject(error)
}
);
/**
* GET请求方式
* @param {*} url
* @param {*} params
*/
export function get(url, params = {}) {
return new Promise((resolve, reject) => {
pc.get(url, {
params: params
})
.then(response => {
if (response.data.code === 200 || response.data.code === 0) {
//返回成功处理 这里传的啥 后续调用的时候 res就是啥
resolve(response.data); //我们后台所有数据都是放在返回的data里所以这里统一处理了
} else {
//错误处理
resolve(response.data);
}
})
.catch(err => {
reject(err);
let message = '请求失败!请检查网络';
//错误返回
if (err.response) {
message = err.response.data.message;
}
console.log(message);
})
})
}
/**提交JSON数据
* @param url
* @param data
* @returns {Promise}
*/
export function postJSON(url, data = {}) {
return new Promise((resolve, reject) => {
pc.post(url, data)
.then(response => {
if (response.data.code === 200 || response.data.code === 0) {
resolve(response.data);
} else {
resolve(response.data);
}
}, err => {
reject(err);
let message = '请求失败!请检查网络';
if (err.response) {
message = err.response.data.message;
}
console.log(message);
})
})
}
/**
* 提交表单数据
* @param {*} url
* @param {*} data
*/
export function postForm(url, data = {}) {
return new Promise((resolve, reject) => {
pc({
method: 'post',
url: url,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}, // 请求头,发送FormData格式的数据,必须是 这种请求头。
data: QS.stringify(data)
}).then(response => {
if (response.data.code === 200 || response.data.code === 0) {
resolve(response.data);
} else {
resolve(response.data);
}
}, err => {
reject(err);
let message = '请求失败!请检查网络';
if (err.response) {
message = err.response.data.message;
}
console.log(message);
})
})
}
调用:单独文件定义方法,导出方法。
import * as PcHttpKit from '@/utils/http/PCHttpKit';
let IM = "sgb-im"
const ImApi = {
// 督办列表
apiDingList:(data)=> PcHttpKit.postJSON(`${IM}/ding/list`, data),
// 督办一键标记已读
dingReadAll:(data)=> PcHttpKit.postJSON(`${IM}/ding/readAll`, data),
// 删除督办
dingRemove:(data)=>PcHttpKit.get(`${IM}/ding/remove`,data)
}
export default ImApi;
页面调用如下:
import api from "@/api/apiDing"; // 页面引入
// 调用方法,获取数据
async getDingList() {
let {data} = await api.apiDingList({type:this.on + 1,userId:this.$store.state.user.no})
this.superviseList = data; // 赋值
},
// 如果不使用async,可以.then
getDingList() {
let data = api.apiDingList({type:this.on + 1,userId:this.$store.state.user.no})
.then((res) => { // 正确执行
this.superviseList = data; // 赋值
}).catch((err) = >{ // 异常
console.log(err)
})
}
上面两种方法的页面调用方式同最后一种页面调用方式相同。
那么基本的封装调用就是这样,细节的东西可以去看官网。
那么,如果没有看懂的话可能是我写的不够详细吧,推荐一篇大神的博文--》vue中Axios的封装和API接口的管理