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接口的管理