雖然vue中axios的使用已經(jīng)十分方便,但是實際我們的日常操作中可能為了接口的規(guī)則一致,來創(chuàng)建一個統(tǒng)一管理的全局方法達到簡化操作.而且在實際接口對接中,我們大多都需要對請求和響應進行攔截來進行token以及回調狀態(tài)碼的處理.那么我基于自己的需求簡單分裝了一下.(之前很少接觸vue,主要用的ng和react,這次新項目想用vue來弄,熟悉一下vue的一些新特性和方法,有啥不對的,歡迎大家批評指正)
前提:
熟悉前端ts, node等等.
1. 安裝axios
npm install axios
2. 攔截器及全局方法編寫
一個http.ts文件進行自己http邏輯的封裝,為了代碼分離,我同時創(chuàng)建interceptors.ts文件進行攔截器邏輯,放在一起也行.
interceptors.ts
(攔截器,進行請求和響應攔截并進行部分邏輯處理)
import axios from 'axios';
import {message} from 'ant-design-vue'; // 這是我引入的antd的組件庫,為了方便彈出吐司
export class Interceptors {
public instance: any;
constructor() {
// 創(chuàng)建axios實例
this.instance = axios.create({timeout: 1000 * 12});
// 初始化攔截器
this.initInterceptors();
}
// 為了讓http.ts中獲取初始化好的axios實例
public getInterceptors() {
return this.instance;
}
// 初始化攔截器
public initInterceptors() {
// 設置post請求頭
this.instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
/**
* 請求攔截器
* 每次請求前,如果存在token則在請求頭中攜帶token
*/
this.instance.interceptors.request.use(
(config) => {
// 登錄流程控制中,根據(jù)本地是否存在token判斷用戶的登錄情況
// 但是即使token存在悬槽,也有可能token是過期的循帐,所以在每次的請求頭中攜帶token
// 后臺根據(jù)攜帶的token判斷用戶的登錄情況,并返回給我們對應的狀態(tài)碼
if (config.headers.isJwt) {
const token = localStorage.getItem('id_token');
if (token) {
config.headers.Authorization = 'Bearer ' + token;
}
}
return config;
},
(error) => {
console.log(error);
},
);
// 響應攔截器
this.instance.interceptors.response.use(
// 請求成功
(res) => {
if (res.headers.authorization) {
localStorage.setItem('id_token', res.headers.authorization);
} else {
if (res.data && res.data.token) {
localStorage.setItem('id_token', res.data.token);
}
}
if (res.status === 200) {
return Promise.resolve(res.data);
} else {
this.errorHandle(res);
return Promise.reject(res.data);
}
},
// 請求失敗
(error) => {
const {response} = error;
if (response) {
// 請求已發(fā)出惠遏,但是不在2xx的范圍
this.errorHandle(response);
return Promise.reject(response.data);
} else {
// 處理斷網(wǎng)的情況
// eg:請求超時或斷網(wǎng)時砾跃,更新state的network狀態(tài)
// network狀態(tài)在app.vue中控制著一個全局的斷網(wǎng)提示組件的顯示隱藏
// 關于斷網(wǎng)組件中的刷新重新獲取數(shù)據(jù),會在斷網(wǎng)組件中說明
message.warn('網(wǎng)絡連接異常,請稍后再試!');
}
});
}
/**
* http握手錯誤
* @param res 響應回調,根據(jù)不同響應進行不同操作
*/
private errorHandle(res: any) {
// 狀態(tài)碼判斷
switch (res.status) {
case 401:
break;
case 403:
break;
case 404:
message.warn('請求的資源不存在');
break;
default:
message.warn('連接錯誤');
}
}
}
http.ts
(http封裝,自己根據(jù)實際情況處理)
/**
* @author keiferju
* @time 2019-08-29 12:57
* @title http請求封裝
* @desc
*
*/
import {Interceptors} from '@/service/interceptors';
import {message, Modal} from 'ant-design-vue'; // 彈吐司
import router from '../router';
export class HttpService {
public axios: any;
public modal: any;
constructor() {
// 獲取axios實例
this.axios = new Interceptors().getInterceptors();
}
/**
* get請求
* @param params 參數(shù)
* @param jwt 是否token校驗
* @param modulename 模塊
* @param operation 接口
* @param flag 標記
* @param verson 版本,默認1.0.0
* @param service 服務,默認services
*/
public getData(params: object, jwt: boolean, modulename: string, operation: string,
flag: string, verson = '1.0.0', service = 'services') {
const url = service + '/' + verson + '/' + modulename + '/' + operation;
const body = {
parameter: {
data: params,
tag: flag,
},
};
return new Promise((resolve, reject) => {
this.axios.get(url, {
params: body,
headers: {isJwt: jwt},
}).then((res) => {
this.resultHandle(res, resolve);
}).catch((err) => {
reject(err.message);
});
});
}
/**
* post請求
* @param params 參數(shù)
* @param jwt 是否token校驗
* @param modulename 模塊
* @param operation 接口
* @param flag 標記
* @param verson 版本,默認1.0.0
* @param service 服務,默認services
*/
public postData(params: object, jwt: boolean, modulename: string, operation: string,
flag: string, verson = '1.0.0', service = 'services') {
const url = service + '/' + verson + '/' + modulename + '/' + operation;
const body = {
data: params,
tag: flag,
};
return new Promise((resolve, reject) => {
this.axios.post(url, body, {
headers: {isJwt: jwt},
}).then((res) => {
this.resultHandle(res, resolve);
}).catch((err) => {
reject(err.message);
});
});
}
/**
*
* @param res
* @param resolve
*/
public resultHandle(res: any, resolve) {
if (res.status > 0) {
resolve(res.data);
} else {
this.errorHandle(res);
}
}
/**
* 服務端狀態(tài)處理,例如中斷性異常,退出異常等等(與攔截器http握手狀態(tài)注意區(qū)分,一般都能分清楚吧)
* @param res
*/
public errorHandle(res: any) {
message.warn(res.msg); // 統(tǒng)一談服務端提示,我們提示統(tǒng)一由服務端提供
// 狀態(tài)碼判斷
switch (res.status) {
case -102:
break;
case -152:
break;
default:
// console.log(other);
}
}
}
3. 掛載
我們定義好攔截器,那么就得把他掛載全局,能讓我們方便使用.
main.ts
import Vue from 'vue';
import App from './App.vue';
import HighchartsVue from 'highcharts-vue';
Vue.config.productionTip = false;
Vue.prototype.$httpService = new HttpService(); // 掛載服務
new Vue({
router,
render: (h) => h(App),
}).$mount('#app');
4. ts橋連(也不知道怎么稱呼,自己從ng時就一直這么稱呼)
行完上一步一定會發(fā)現(xiàn)報錯啊,$httpService是個啥,不存在啊,這是因為ts的特性導致.
main.ts的同級目錄創(chuàng)建一個xx.d.ts文件.
import {HttpService} from './service/http';
declare module 'vue/types/vue' {
interface Vue {
$httpService: HttpService;
}
}
5. 使用
在其它組件中使用,直接用this調用,不用再去引用,但是小心在某個this指向變了的回調中使用時找不到,至于怎么怎么解決應該都懂.
this.$httpService.postData({}, true, 'execute', 'xxx', 'tag').then((result) => {
// doing
}, (error) => {
console.log(error);
});
最后:
這是在ts下的封裝,js的話更簡單點,甚至應該會更簡單點(會少一些步驟,網(wǎng)上教程應該很多).掛載http工具的方式平時也適合我們定義全局工具類或者服務.