項(xiàng)目實(shí)踐 - Axios進(jìn)階封裝
axios二次封裝解決了什么問題?(項(xiàng)目常用)
axios二次封裝:就是把大部分接口公共的參數(shù)配置提取出來統(tǒng)一進(jìn)行處理。
1、代碼封裝,重用性高,減少代碼量,減低維護(hù)難度。
2、統(tǒng)一處理一些常規(guī)的問題一勞永逸,如http錯(cuò)誤。
3、攔截請(qǐng)求和響應(yīng),提前對(duì)數(shù)據(jù)進(jìn)行處理,如獲取token,修改配置項(xiàng)。
Axios基礎(chǔ)配置- 實(shí)踐
1) 全局的 axios 默認(rèn)值
- axios.defaults.baseURL = 'https://api.example.com';
- axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
- axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
2) 自定義實(shí)例默認(rèn)值
- // 創(chuàng)建實(shí)例時(shí)設(shè)置配置的默認(rèn)值
- var instance = axios.create({
- baseURL: 'https://api.example.com'
- });
- // 在實(shí)例已創(chuàng)建后修改默認(rèn)值
- instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
3) 區(qū)分環(huán)境配置
- let env = "dev";
- switch (env) {
- case 'dev':
- axios.defaults.baseURL = "http://127.0.0.1:8888";
- break;
- case 'test':
- axios.defaults.baseURL = "http://114.27.34.1:8888";
- break;
- case 'pro':
- axios.defaults.baseURL = "http://api.zhufeng.cn";
- break;
- }
4) 數(shù)據(jù)格式配置
- axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded';
- // axios.defaults.headers.common['Content-Type'] = 'application/x-www-form-urlencoded';
- // axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
- axios.defaults.transformRequest = function (data, headers) {
- let ContentType = headers['Content-Type'] || headers.common['Content-Type'] || headers.post['Content-Type'] || 'application/json';
- if (ContentType === "application/json") {
- return JSON.stringify(data);
- }
- if (ContentType === "application/x-www-form-urlencoded") {
- return Qs.stringify(data);
- }
- return data;
- };
項(xiàng)目實(shí)踐-數(shù)據(jù)格式
- service.interceptors.request.use(
- (config) => {
- // 開發(fā)環(huán)境引入包裝api
- config.url = `${BASE_URL}${config.url}`;
- config.headers['Cache-Control'] = 'no-cache,no-store,must-revalidate,max-age=-1,private';
- // post請(qǐng)求并且需要將data以form data 形式傳給后端 需要傳一個(gè)formType為true boolean
- if (config.method === 'post' && config.formType === true) {
- config.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
- config.data = qs.stringify(config.data);
- }
- return config;
- },
- (error) => {
- // Do something with request error
- Promise.reject(error);
- }
- );
5) 攔截器
- // 添加請(qǐng)求攔截器
- axios.interceptors.request.use(function (config) {
- // 在發(fā)送請(qǐng)求之前做些什么
- return config;
- }, function (error) {
- // 對(duì)請(qǐng)求錯(cuò)誤做些什么
- return Promise.reject(error);
- });
- // 添加響應(yīng)攔截器
- axios.interceptors.response.use(function (response) {
- // 對(duì)響應(yīng)數(shù)據(jù)做點(diǎn)什么
- return response;
- }, function (error) {
- // 對(duì)響應(yīng)錯(cuò)誤做點(diǎn)什么
- return Promise.reject(error);
- });
6) 響應(yīng)的錯(cuò)誤處理封裝
interceptor作用就是攔截,可以針對(duì)請(qǐng)求參數(shù)和響應(yīng)結(jié)果進(jìn)行攔截處理,一般在項(xiàng)目當(dāng)中,主要針對(duì)接口常規(guī)報(bào)錯(cuò)、網(wǎng)絡(luò)報(bào)錯(cuò)、系統(tǒng)超時(shí)、權(quán)限認(rèn)證等做攔截處理。
- axios.interceptors.response.use(function (response) {
- // 把獲取的響應(yīng)主體信息返回
- return response.data;
- }, function (reason) {
- // 失敗:網(wǎng)絡(luò)、狀態(tài)碼(Axios失敗)
- let response = reason.response;
- if (response) {
- // 狀態(tài)碼不是2開頭的
- switch (response.status) {
- //400 參數(shù)
- //401/403 Token
- //404 地址
- //500/503 服務(wù)器
- }
- } else {
- // 網(wǎng)絡(luò) / (超時(shí) / 中斷請(qǐng)求 -> code: "ECONNABORTED") ...
- if (reason && reason.code === "ECONNABORTED") {}
- if (!navigator.onLine) {}
- }
- return reason;
- });
一般項(xiàng)目,這樣就沒問題了,一套公共的參數(shù)配置。剩下都是請(qǐng)求的時(shí)候單獨(dú)再配置即可。
Axios配置- 原理與源碼
1) HTTP 攔截器的設(shè)計(jì)與實(shí)現(xiàn)
對(duì)于大多數(shù) SPA 應(yīng)用程序來說, 通常會(huì)使用 token 進(jìn)行用戶的身份認(rèn)證。這就要求在認(rèn)證通過后,我們需要在每個(gè)請(qǐng)求上都攜帶認(rèn)證信息。如果在考慮對(duì)響應(yīng)進(jìn)行統(tǒng)一處理的話,我們的 request 函數(shù)將變得越來越龐大,也越來越難維護(hù)。那么對(duì)于這個(gè)問題,Axios 為我們提供了解決方案 —— 攔截器。
Axios 是一個(gè)基于 Promise 的 HTTP 客戶端,而 HTTP 協(xié)議是基于請(qǐng)求和響應(yīng):
所以 Axios 提供了請(qǐng)求攔截器和響應(yīng)攔截器來分別處理請(qǐng)求和響應(yīng)。
1) 請(qǐng)求攔截器:該類攔截器的作用是在請(qǐng)求發(fā)送前統(tǒng)一執(zhí)行某些操作,比如在請(qǐng)求頭中添加 token 字段。
2) 響應(yīng)攔截器:該類攔截器的作用是在接收到服務(wù)器響應(yīng)后統(tǒng)一執(zhí)行某些操作,比如發(fā)現(xiàn)響應(yīng)狀態(tài)碼為 401 時(shí),自動(dòng)跳轉(zhuǎn)到登錄頁。
2) 二次封裝配置代碼:(參考)
- import axios from 'axios';
- import qs from 'qs';
- /*
- * 根據(jù)環(huán)境變量區(qū)分接口的默認(rèn)地址
- */
- switch (process.env.NODE_ENV) {
- case "production":
- axios.defaults.baseURL = "http://api.zhufengpeixun.cn";
- break;
- case "test":
- axios.defaults.baseURL = "http://192.168.20.12:8080";
- break;
- default:
- axios.defaults.baseURL = "http://127.0.0.1:3000";
- }
- /*
- * 設(shè)置超時(shí)時(shí)間和跨域是否允許攜帶憑證
- */
- axios.defaults.timeout = 10000;
- axios.defaults.withCredentials = true;
- /*
- * 設(shè)置請(qǐng)求傳遞數(shù)據(jù)的格式(看服務(wù)器要求什么格式)
- * x-www-form-urlencoded
- */
- axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded';
- axios.defaults.transformRequest = data => qs.stringify(data);
- /*
- * 設(shè)置請(qǐng)求攔截器
- * 客戶端發(fā)送請(qǐng)求 - > [請(qǐng)求攔截器] - > 服務(wù)器
- * TOKEN校驗(yàn)(JWT):接收服務(wù)器返回的token,存儲(chǔ)到vuex/本地存儲(chǔ)中,每一次向服務(wù)器發(fā)請(qǐng)求,我們應(yīng)該把token帶上
- */
- axios.interceptors.request.use(config => {
- // 攜帶上token
- let token = localStorage.getItem('token');
- token && (config.headers.Authorization = token);
- return config;
- }, error => {
- return Promise.reject(error);
- });
- /*
- * 響應(yīng)攔截器
- * 服務(wù)器返回信息 -> [攔截的統(tǒng)一處理] -> 客戶端JS獲取到信息
- */
- axios.defaults.validateStatus = status => {
- // 自定義響應(yīng)成功的HTTP狀態(tài)碼
- return /^(2|3)\d{2}$/.test(status);
- };
- axios.interceptors.response.use(response => {
- return response.data;
- }, error => {
- let {
- response
- } = error;
- if (response) {
- //=>服務(wù)器最起碼返回結(jié)果了
- switch (response.status) {
- case 401: //=>權(quán)限
- break;
- case 403: //=>服務(wù)器拒絕執(zhí)行(token過期)
- break;
- case 404: //=>找不到頁面
- break;
- }
- } else {
- //=>服務(wù)器連結(jié)果都沒有返回
- if (!window.navigator.onLine) {
- // 斷網(wǎng)處理:可以跳轉(zhuǎn)到斷網(wǎng)頁面
- return;
- }
- return Promise.reject(error);
- }
- });
- export default axios;
【編輯推薦】