axios詳解以及完整封裝方法

来源:https://www.cnblogs.com/xw-01/archive/2023/07/15/17556298.html
-Advertisement-
Play Games

""" # 一、axios是什麼 Axios 是一個基於 promise 網路請求庫,作用於node.js 和瀏覽器中。 它是 isomorphic 的(即同一套代碼可以運行在瀏覽器和node.js中)。在服務端它使用原生 node.js http 模塊, 而在客戶端 (瀏覽端) 則使用 XMLHt ...


"""


一、axios是什麼

Axios 是一個基於 promise 網路請求庫,作用於node.js 和瀏覽器中。 它是 isomorphic 的(即同一套代碼可以運行在瀏覽器和node.js中)。在服務端它使用原生 node.js http 模塊, 而在客戶端 (瀏覽端) 則使用 XMLHttpRequests。


axios有以下特性:

  • 從瀏覽器創建 XMLHttpRequests
  • 從 node.js 創建 http 請求
  • 支持 Promise API
  • 攔截請求和響應
  • 轉換請求和響應數據
  • 取消請求
  • 自動轉換JSON數據
  • 客戶端支持防禦XSRF

axios可以請求的方法:

  • get:獲取數據,請求指定的信息,返回實體對象
  • post:向指定資源提交數據(例如表單提交或文件上傳)
  • put:更新數據,從客戶端向伺服器傳送的數據取代指定的文檔的內容
  • patch:更新數據,是對put方法的補充,用來對已知資源進行局部更新
  • delete:請求伺服器刪除指定的數據
  • head:獲取報文首部

請求方法別名

為了方便起見,axios為所有支持的請求方法提供了別名:

  • axios(config)
  • axios.request(config)
  • axios.get(url [,config])
  • axios.post(url [,data [,config]])
  • axios.put(url [,data [,config]])
  • axios.delete(url [,config])
  • axios.patch(url [,data [,config]])
  • axios.head(url [,config])

二.axios實例及配置方法

1.創建axios實例
axios.create([config])

可以同時創建多個axios實例。

示例代碼
"""

const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});

"""
實例方法

以下是可用的實例方法。指定的配置將與實例的配置合併。

  • axios#request(config)

  • axios#get(url[, config])

  • axios#delete(url[, config])

  • axios#head(url[, config])

  • axios#options(url[, config])

  • axios#post(url[, data[, config]])

  • axios#put(url[, data[, config]])

  • axios#patch(url[, data[, config]])

  • axios#getUri([config])


2.配置方法

配置對象常用的配置項:

這些是創建請求時可以用的配置選項。只有 url 是必需的。如果沒有指定 method,請求將預設使用 GET 方法。更多配置項請查看官方文檔

"""

{
  // 路徑url
  url: '/user',

  // 請求方法,預設get
  method: 'get', 

  //基礎url,最終請求的url是 baseURL+url拼接,所以再全局設置預設,可以使得發送請求時的url變得簡潔
  baseURL: 'https://some-domain.com/api/',

  //設置請求頭
  headers: {'X-Requested-With': 'XMLHttpRequest'},

  //設置請求url的query參數,可以使得url簡潔。
  //比如url是https://some-domain.com/api/user  然後params如下設置,那麼最終的url是:
  //https://some-domain.com/api/user?ID=12345&name=Jack
  params: {
	ID: 12345,
	name:"Jack"
  },

 //設置請求體
  data: {
	firstName: 'Fred'
  },

  //設置請求的另外一種格式,不過這個是直接設置字元串的
  data: 'Country=Brasil&City=Belo Horizonte',

 //請求超時,單位毫秒,預設0,不超時。
  timeout: 1000,

  //響應數據類型,預設json
  responseType: 'json', 

  //響應數據的編碼規則,預設utf-8
  responseEncoding: 'utf8',

	//響應體的最大長度 
  maxContentLength: 2000,

  // 請求體的最大長度
  maxBodyLength: 2000,

  //設置響應狀態碼為多少時是成功,調用resolve,否則調用reject失敗
  //預設是大於等於200,小於300
  validateStatus: function (status) {
	return status >= 200 && status < 300; 
  },

"""


預設配置

可以設置全局預設配置,是為了避免多種重覆配置在不同請求中重覆,比如baseURL、timeout等,這裡設置baseURL。


全局 axios 預設值
"""

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';

"""
自定義實例預設值

"""

// 創建實例時配置預設值
const instance = axios.create({
  baseURL: 'https://api.example.com'
});

// 創建實例後修改預設值
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;

""""


配置的優先順序

配置將會按優先順序進行合併。它的順序是:在 lib/defaults.js 中找到的庫預設值,然後是實例的 defaults 屬性,最後是請求的 config 參數。後面的優先順序要高於前面的。


三、攔截器

在請求或響應被 then 或 catch 處理前攔截它們,自定義的axios實例也可添加攔截器,如:
"""

const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});

"""
請求攔截器

示例代碼:

"""

// 添加請求攔截器
axios.interceptors.request.use(function (config) {
	// 在發送請求之前做些什麼
	return config;
  }, function (error) {
	// 對請求錯誤做些什麼
	return Promise.reject(error);
  });

"""
響應攔截器

示例代碼:

"""

// 添加響應攔截器
axios.interceptors.response.use(function (response) {
	// 2xx 範圍內的狀態碼都會觸發該函數。
	// 對響應數據做點什麼
	return response;
  }, function (error) {
	// 超出 2xx 範圍的狀態碼都會觸發該函數。
	// 對響應錯誤做點什麼
	return Promise.reject(error);
  });

"""
取消攔截器

示例代碼:

"""

const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);

"""


四、取消請求

註意:從 v0.22.0 開始,Axios 支持以 fetch API 方式—— AbortController 取消請求,CancelToken API被棄用

這裡我們兩種方法都介紹一下,使用過程中能用 AbortController 就儘量別用 CancelToken

AbortController

"""

const controller = new AbortController();

axios.get('/foo/bar', {
   signal: controller.signal
}).then(function(response) {
   //...
});
// 取消請求
controller.abort()

"""
CancelToken

"""

let source = axios.CancelToken.source();

axios.get('/users/12345',{
				cancelToken: source.token
			}).then(res=>{
				console.log(res)
			}).catch(err=>{
				//取消請求後會執行該方法
				console.log(err)
			})

//取消請求,參數可選,該參數信息會發送到請求的catch中
source.cancel('取消後的信息');

"""
也可以通過傳遞一個 executor 函數到 CancelToken 的構造函數來創建一個 cancel token:

"""

const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
	// executor 函數接收一個 cancel 函數作為參數
	cancel = c;
  })
});

// 取消請求
cancel();

"""
註意: 可以使用同一個 cancel token 或 signal 取消多個請求


五、axios封裝

先設計我們想要這個通用請求能達到什麼樣的效果:

  • 優化配置,設置預設配置項(responseType、跨域攜帶cookie、token、超時設置)
  • 統一設置請求頭
  • 根據環境設置 baseURL
  • 通過 Axios 方法直接發起請求
  • 添加請求攔截器
  • 添加響應攔截器
  • 導出 Promise 對象
  • 封裝 Post 方法,精簡 post 請求方式
  • 封裝 Get 方法,精簡 get 請求方式
  • 請求成功,配置業務狀態碼
  • 全局的loading配置

一、axios的封裝
在vue項目中,和後臺交互獲取數據這塊,我們通常使用的是axios庫,它是基於promise的http庫,可運行在瀏覽器端和node.js中。他有很多優秀的特性,例如攔截請求和響應、取消請求、轉換json、客戶端防禦XSRF等。所以我們的尤大大也是果斷放棄了對其官方庫vue-resource的維護,直接推薦我們使用axios庫。如果還對axios不瞭解的,可以移步axios文檔。

安裝
npm install axios; // 安裝axios
引入
一般我會在項目的src目錄中,新建一個request文件夾,然後在裡面新建一個http.js和一個api.js文件。http.js文件用來封裝我們的axios,api.js用來統一管理我們的介面。

// 在http.js中引入axios
import axios from 'axios'; // 引入axios
import QS from 'qs'; // 引入qs模塊,用來序列化post類型的數據,後面會提到
// vant的toast提示框組件,大家可根據自己的ui組件更改。
import { Toast } from 'vant'; 
環境的切換
我們的項目環境可能有開發環境、測試環境和生產環境。我們通過node的環境變數來匹配我們的預設的介面url首碼。axios.defaults.baseURL可以設置axios的預設請求地址就不多說了。

// 環境的切換
if (process.env.NODE_ENV == 'development') {    
	axios.defaults.baseURL = 'https://www.baidu.com';} 
else if (process.env.NODE_ENV == 'debug') {    
	axios.defaults.baseURL = 'https://www.ceshi.com';
} 
else if (process.env.NODE_ENV == 'production') {    
	axios.defaults.baseURL = 'https://www.production.com';
}
設置請求超時
通過axios.defaults.timeout設置預設的請求超時時間。例如超過了10s,就會告知用戶當前請求超時,請刷新等。

axios.defaults.timeout = 10000;
post請求頭的設置
post請求的時候,我們需要加上一個請求頭,所以可以在這裡進行一個預設的設置,即設置post的請求頭為application/x-www-form-urlencoded;charset=UTF-8

axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
請求攔截
我們在發送請求前可以進行一個請求的攔截,為什麼要攔截呢,我們攔截請求是用來做什麼的呢?比如,有些請求是需要用戶登錄之後才能訪問的,或者post請求的時候,我們需要序列化我們提交的數據。這時候,我們可以在請求被髮送之前進行一個攔截,從而進行我們想要的操作。

請求攔截
// 先導入vuex,因為我們要使用到裡面的狀態對象
// vuex的路徑根據自己的路徑去寫
import store from '@/store/index';

// 請求攔截器axios.interceptors.request.use(    
	config => {        
		// 每次發送請求之前判斷vuex中是否存在token        
		// 如果存在,則統一在http請求的header都加上token,這樣後臺根據token判斷你的登錄情況
		// 即使本地存在token,也有可能token是過期的,所以在響應攔截器中要對返回狀態進行判斷 
		const token = store.state.token;        
		token && (config.headers.Authorization = token);        
		return config;    
	},    
	error => {        
		return Promise.error(error);    
})
這裡說一下token,一般是在登錄完成之後,將用戶的token通過localStorage或者cookie存在本地,然後用戶每次在進入頁面的時候(即在main.js中),會首先從本地存儲中讀取token,如果token存在說明用戶已經登陸過,則更新vuex中的token狀態。然後,在每次請求介面的時候,都會在請求的header中攜帶token,後臺人員就可以根據你攜帶的token來判斷你的登錄是否過期,如果沒有攜帶,則說明沒有登錄過。這時候或許有些小伙伴會有疑問了,就是每個請求都攜帶token,那麼要是一個頁面不需要用戶登錄就可以訪問的怎麼辦呢?其實,你前端的請求可以攜帶token,但是後臺可以選擇不接收啊!

響應的攔截
// 響應攔截器
axios.interceptors.response.use(    
	response => {   
		// 如果返回的狀態碼為200,說明介面請求成功,可以正常拿到數據     
		// 否則的話拋出錯誤
		if (response.status === 200) {            
			return Promise.resolve(response);        
		} else {            
			return Promise.reject(response);        
		}    
	},    
	// 伺服器狀態碼不是2開頭的的情況
	// 這裡可以跟你們的後臺開發人員協商好統一的錯誤狀態碼    
	// 然後根據返回的狀態碼進行一些操作,例如登錄過期提示,錯誤提示等等
	// 下麵列舉幾個常見的操作,其他需求可自行擴展
	error => {            
		if (error.response.status) {            
			switch (error.response.status) {                
				// 401: 未登錄
				// 未登錄則跳轉登錄頁面,並攜帶當前頁面的路徑
				// 在登錄成功後返回當前頁面,這一步需要在登錄頁操作。                
				case 401:                    
					router.replace({                        
						path: '/login',                        
						query: { 
							redirect: router.currentRoute.fullPath 
						}
					});
					break;

            // 403 token過期
            // 登錄過期對用戶進行提示
            // 清除本地token和清空vuex中token對象
            // 跳轉登錄頁面                
            case 403:
                 Toast({
                    message: '登錄過期,請重新登錄',
                    duration: 1000,
                    forbidClick: true
                });
                // 清除token
                localStorage.removeItem('token');
                store.commit('loginSuccess', null);
                // 跳轉登錄頁面,並將要瀏覽的頁面fullPath傳過去,登錄成功後跳轉需要訪問的頁面 
                setTimeout(() => {                        
                    router.replace({                            
                        path: '/login',                            
                        query: { 
                            redirect: router.currentRoute.fullPath 
                        }                        
                    });                    
                }, 1000);                    
                break; 

            // 404請求不存在
            case 404:
                Toast({
                    message: '網路請求不存在',
                    duration: 1500,
                    forbidClick: true
                });
                break;
            // 其他錯誤,直接拋出錯誤提示
            default:
                Toast({
                    message: error.response.data.message,
                    duration: 1500,
                    forbidClick: true
                });
        }
        return Promise.reject(error.response);
    }
}    
});
響應攔截器很好理解,就是伺服器返回給我們的數據,我們在拿到之前可以對他進行一些處理。例如上面的思想:如果後臺返回的狀態碼是200,則正常返回數據,否則的根據錯誤的狀態碼類型進行一些我們需要的錯誤,其實這裡主要就是進行了錯誤的統一處理和沒登錄或登錄過期後調整登錄頁的一個操作。

要註意的是,上面的Toast()方法,是我引入的vant庫中的toast輕提示組件,你根據你的ui庫,對應使用你的一個提示組件。

封裝get方法和post方法
我們常用的ajax請求方法有get、post、put等方法,相信小伙伴都不會陌生。axios對應的也有很多類似的方法,不清楚的可以看下文檔。但是為了簡化我們的代碼,我們還是要對其進行一個簡單的封裝。下麵我們主要封裝兩個方法:get和post。

get方法:我們通過定義一個get函數,get函數有兩個參數,第一個參數表示我們要請求的url地址,第二個參數是我們要攜帶的請求參數。get函數返回一個promise對象,當axios其請求成功時resolve伺服器返回 值,請求失敗時reject錯誤值。最後通過export拋出get函數。

/**
 * get方法,對應get請求
 * @param {String} url [請求的url地址]
 * @param {Object} params [請求時攜帶的參數]
 */
export function get(url, params){    
	return new Promise((resolve, reject) =>{        
		axios.get(url, {            
			params: params        
		}).then(res => {
			resolve(res.data);
		}).catch(err =>{
			reject(err.data)        
	})    
});}
post方法:原理同get基本一樣,但是要註意的是,post方法必須要使用對提交從參數對象進行序列化的操作,所以這裡我們通過node的qs模塊來序列化我們的參數。這個很重要,如果沒有序列化操作,後臺是拿不到你提交的數據的。這就是文章開頭我們import QS from 'qs';的原因。如果不明白序列化是什麼意思的,就百度一下吧,答案一大堆。

/** 
 * post方法,對應post請求 
 * @param {String} url [請求的url地址] 
 * @param {Object} params [請求時攜帶的參數] 
 */
export function post(url, params) {
	return new Promise((resolve, reject) => {
		 axios.post(url, QS.stringify(params))
		.then(res => {
			resolve(res.data);
		})
		.catch(err =>{
			reject(err.data)
		})
	});
}
這裡有個小細節說下,axios.get()方法和axios.post()在提交數據時參數的書寫方式還是有區別的。區別就是,get的第二個參數是一個{},然後這個對象的params屬性值是一個參數對象的。而post的第二個參數就是一個參數對象。兩者略微的區別要留意哦!

axios的封裝基本就完成了,下麵再簡單說下api的統一管理。
整齊的api就像電路板一樣,即使再複雜也能很清晰整個線路。上面說了,我們會新建一個api.js,然後在這個文件中存放我們所有的api介面。

首先我們在api.js中引入我們封裝的get和post方法

/**   
 * api介面統一管理
 */
import { get, post } from './http'
現在,例如我們有這樣一個介面,是一個post請求:

http://www.baiodu.com/api/v1/users/my_address/address_edit_before
我們可以在api.js中這樣封裝:

export const apiAddress = p => post('api/v1/users/my_address/address_edit_before', p);
我們定義了一個apiAddress方法,這個方法有一個參數p,p是我們請求介面時攜帶的參數對象。而後調用了我們封裝的post方法,post方法的第一個參數是我們的介面地址,第二個參數是apiAddress的p參數,即請求介面時攜帶的參數對象。最後通過export導出apiAddress。

然後在我們的頁面中可以這樣調用我們的api介面:

import { apiAddress } from '@/request/api';// 導入我們的api介面
export default {        
	name: 'Address',    
	created () {
		this.onLoad();
	},
	methods: {            
		// 獲取數據            
		onLoad() {
			// 調用api介面,並且提供了兩個參數                
			apiAddress({                    
				type: 0,                    
				sort: 1                
			}).then(res => {
				// 獲取數據成功後的其他操作
				………………                
			})            
		}        
	}
}
其他的api介面,就在pai.js中繼續往下麵擴展就可以了。友情提示,為每個介面寫好註釋哦!!!

api介面管理的一個好處就是,我們把api統一集中起來,如果後期需要修改介面,我們就直接在api.js中找到對應的修改就好了,而不用去每一個頁面查找我們的介面然後再修改會很麻煩。關鍵是,萬一修改的量比較大,就規格gg了。還有就是如果直接在我們的業務代碼修改介面,一不小心還容易動到我們的業務代碼造成不必要的麻煩。

好了,最後把完成的axios封裝代碼奉上。

/**axios封裝
 * 請求攔截、相應攔截、錯誤統一處理
 */
import axios from 'axios';import QS from 'qs';
import { Toast } from 'vant';
import store from '../store/index'

// 環境的切換
if (process.env.NODE_ENV == 'development') {    
	axios.defaults.baseURL = '/api';
} else if (process.env.NODE_ENV == 'debug') {    
	axios.defaults.baseURL = '';
} else if (process.env.NODE_ENV == 'production') {    
	axios.defaults.baseURL = 'http://api.123dailu.com/';
}

// 請求超時時間
axios.defaults.timeout = 10000;

// post請求頭
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';

// 請求攔截器
axios.interceptors.request.use(    
	config => {
		// 每次發送請求之前判斷是否存在token,如果存在,則統一在http請求的header都加上token,不用每次請求都手動添加了
		// 即使本地存在token,也有可能token是過期的,所以在響應攔截器中要對返回狀態進行判斷
		const token = store.state.token;        
		token && (config.headers.Authorization = token);        
		return config;    
	},    
	error => {        
		return Promise.error(error);    
	})

// 響應攔截器
axios.interceptors.response.use(    
	response => {        
		if (response.status === 200) {            
			return Promise.resolve(response);        
		} else {            
			return Promise.reject(response);        
		}    
	},
	// 伺服器狀態碼不是200的情況    
	error => {        
		if (error.response.status) {            
			switch (error.response.status) {                
				// 401: 未登錄                
				// 未登錄則跳轉登錄頁面,並攜帶當前頁面的路徑                
				// 在登錄成功後返回當前頁面,這一步需要在登錄頁操作。                
				case 401:                    
					router.replace({                        
						path: '/login',                        
						query: { redirect: router.currentRoute.fullPath } 
					});
					break;
				// 403 token過期                
				// 登錄過期對用戶進行提示                
				// 清除本地token和清空vuex中token對象                
				// 跳轉登錄頁面                
				case 403:                     
					Toast({                        
						message: '登錄過期,請重新登錄',                        
						duration: 1000,                        
						forbidClick: true                    
					});                    
					// 清除token                    
					localStorage.removeItem('token');                    
					store.commit('loginSuccess', null);                    
					// 跳轉登錄頁面,並將要瀏覽的頁面fullPath傳過去,登錄成功後跳轉需要訪問的頁面
					setTimeout(() => {                        
						router.replace({                            
							path: '/login',                            
							query: { 
								redirect: router.currentRoute.fullPath 
							}                        
						});                    
					}, 1000);                    
					break; 
				// 404請求不存在                
				case 404:                    
					Toast({                        
						message: '網路請求不存在',                        
						duration: 1500,                        
						forbidClick: true                    
					});                    
				break;                
				// 其他錯誤,直接拋出錯誤提示                
				default:                    
					Toast({                        
						message: error.response.data.message,                        
						duration: 1500,                        
						forbidClick: true                    
					});            
			}            
			return Promise.reject(error.response);        
		}       
	}
);
/** 
 * get方法,對應get請求 
 * @param {String} url [請求的url地址] 
 * @param {Object} params [請求時攜帶的參數] 
 */
export function get(url, params){    
	return new Promise((resolve, reject) =>{        
		axios.get(url, {            
			params: params        
		})        
		.then(res => {            
			resolve(res.data);        
		})        
		.catch(err => {            
			reject(err.data)        
		})    
	});
}
/** 
 * post方法,對應post請求 
 * @param {String} url [請求的url地址] 
 * @param {Object} params [請求時攜帶的參數] 
 */
export function post(url, params) {    
	return new Promise((resolve, reject) => {         
		axios.post(url, QS.stringify(params))        
		.then(res => {            
			resolve(res.data);        
		})        
		.catch(err => {            
			reject(err.data)        
		})    
	});
}
axios的封裝根據需求的不同而不同。
1.優化axios封裝,去掉之前的get和post

2.斷網情況處理

3.更加模塊化的api管理

4.介面功能變數名稱有多個的情況

5.api掛載到vue.prototype上省去引入的步驟

http.js中axios封裝的優化,先直接貼代碼:

/**
 * axios封裝
 * 請求攔截、響應攔截、錯誤統一處理
 */
import axios from 'axios';
import router from '../router';
import store from '../store/index';
import { Toast } from 'vant';

/** 
 * 提示函數 
 * 禁止點擊蒙層、顯示一秒後關閉
 */
const tip = msg => {    
	Toast({        
		message: msg,        
		duration: 1000,        
		forbidClick: true    
	});
}

/** 
 * 跳轉登錄頁
 * 攜帶當前頁面路由,以期在登錄頁面完成登錄後返回當前頁面
 */
const toLogin = () => {
	router.replace({
		path: '/login',        
		query: {
			redirect: router.currentRoute.fullPath
		}
	});
}

/** 
 * 請求失敗後的錯誤統一處理 
 * @param {Number} status 請求失敗的狀態碼
 */
const errorHandle = (status, other) => {
	// 狀態碼判斷
	switch (status) {
		// 401: 未登錄狀態,跳轉登錄頁
		case 401:
			toLogin();
			break;
		// 403 token過期
		// 清除token並跳轉登錄頁
		case 403:
			tip('登錄過期,請重新登錄');
			localStorage.removeItem('token');
			store.commit('loginSuccess', null);
			setTimeout(() => {
				toLogin();
			}, 1000);
			break;
		// 404請求不存在
		case 404:
			tip('請求的資源不存在'); 
			break;
		default:
			console.log(other);   
		}}

// 創建axios實例
var instance = axios.create({    timeout: 1000 * 12});
// 設置post請求頭
instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
/** 
 * 請求攔截器 
 * 每次請求前,如果存在token則在請求頭中攜帶token 
 */ 
instance.interceptors.request.use(    
	config => {        
		// 登錄流程式控制制中,根據本地是否存在token判斷用戶的登錄情況        
		// 但是即使token存在,也有可能token是過期的,所以在每次的請求頭中攜帶token        
		// 後臺根據攜帶的token判斷用戶的登錄情況,並返回給我們對應的狀態碼        
		// 而後我們可以在響應攔截器中,根據狀態碼進行一些統一的操作。        
		const token = store.state.token;        
		token && (config.headers.Authorization = token);        
		return config;    
	},    
	error => Promise.error(error))

// 響應攔截器
instance.interceptors.response.use(    
	// 請求成功
	res => res.status === 200 ? Promise.resolve(res) : Promise.reject(res),    
	// 請求失敗
	error => {
		const { response } = error;
		if (response) {
			// 請求已發出,但是不在2xx的範圍 
			errorHandle(response.status, response.data.message);
			return Promise.reject(response);
		} else {
			// 處理斷網的情況
			// eg:請求超時或斷網時,更新state的network狀態
			// network狀態在app.vue中控制著一個全局的斷網提示組件的顯示隱藏
			// 關於斷網組件中的刷新重新獲取數據,會在斷網組件中說明
			if (!window.navigator.onLine) {
			   store.commit('changeNetwork', false);
			} else {
				return Promise.reject(error);
			}
		}
	});

export default instance;
這個axios和之前的大同小異,做瞭如下幾點改變:

1.去掉了之前get和post方法的封裝,通過創建一個axios實例然後export default方法導出,這樣使用起來更靈活一些。

2.去掉了通過環境變數控制baseUrl的值。考慮到介面會有多個不同功能變數名稱的情況,所以準備通過js變數來控制介面功能變數名稱。這點具體在api里會介紹。

3.增加了請求超時,即斷網狀態的處理。說下思路,當斷網時,通過更新vuex中network的狀態來控制斷網提示組件的顯示隱藏。斷網提示一般會有重新載入數據的操作,這步會在後面對應的地方介紹。

4.公用函數進行抽出,簡化代碼,儘量保證單一職責原則。

下麵說下api這塊,考慮到一下需求:

1.更加模塊化

2.更方便多人開發,有效減少解決命名衝突

3.處理介面功能變數名稱有多個情況

這裡這裡呢新建了一個api文件夾,裡面有一個index.js和一個base.js,以及多個根據模塊劃分的介面js文件。index.js是一個api的出口,base.js管理介面功能變數名稱,其他js則用來管理各個模塊的介面。

先放index.js代碼:

/** 
 * api介面的統一齣口
 */
// 文章模塊介面
import article from '@/api/article';
// 其他模塊的介面……

// 導出介面
export default {    
	article,
	// ……
}
index.js是一個api介面的出口,這樣就可以把api介面根據功能劃分為多個模塊,利於多人協作開發,比如一個人只負責一個模塊的開發等,還能方便每個模塊中介面的命名哦。

base.js:

/**
 * 介面功能變數名稱的管理
 */
const base = {    
	sq: 'https://xxxx111111.com/api/v1',    
	bd: 'http://xxxxx22222.com/api'
}

export default base;
通過base.js來管理我們的介面功能變數名稱,不管有多少個都可以通過這裡進行介面的定義。即使修改起來,也是很方便的。

最後就是介面模塊的說明,例如上面的article.js:

/**
 * article模塊介面列表
 */

import base from './base'; // 導入介面功能變數名稱列表
import axios from '@/utils/http'; // 導入http中創建的axios實例
import qs from 'qs'; // 根據需求是否導入qs模塊

const article = {    
	// 新聞列表    
	articleList () {        
		return axios.get(`${base.sq}/topics`);    
	},    
	// 新聞詳情,演示    
	articleDetail (id, params) {        
		return axios.get(`${base.sq}/topic/${id}`, {            
			params: params        
		});    
	},
	// post提交    
	login (params) {        
		return axios.post(`${base.sq}/accesstoken`, qs.stringify(params));    
	}
	// 其他介面…………
}

export default article;
1.通過直接引入我們封裝好的axios實例,然後定義介面、調用axios實例並返回,可以更靈活的使用axios,比如你可以對post請求時提交的數據進行一個qs序列化的處理等。

2.請求的配置更靈活,你可以針對某個需求進行一個不同的配置。關於配置的優先順序,axios文檔說的很清楚,這個順序是:在 lib/defaults.js 找到的庫的預設值,然後是實例的 defaults 屬性,最後是請求的 config 參數。後者將優先於前者。

3.restful風格的介面,也可以通過這種方式靈活的設置api介面地址。

最後,為了方便api的調用,我們需要將其掛載到vue的原型上。在main.js中:

import Vue from 'vue'
import App from './App'
import router from './router' // 導入路由文件
import store from './store' // 導入vuex文件
import api from './api' // 導入api介面

Vue.prototype.$api = api; // 將api掛載到vue的原型上
然後我們可以在頁面中這樣調用介面,eg:

methods: {    
	onLoad(id) {      
		this.$api.article.articleDetail(id, {        
			api: 123      
		}).then(res=> {
			// 執行某些操作      
		})    
	}  
}
再提一下斷網的處理,這裡只做一個簡單的示例:

<template>  
	<div id="app">    
		<div v-if="!network">      
			<h3>我沒網了</h3>      
			<div @click="onRefresh">刷新</div>      
		</div>    
		<router-view/>      
	</div>
</template>

<script>
	import { mapState } from 'vuex';
	export default {  
		name: 'App',  
		computed: {    
			...mapState(['network'])  
		},  
		methods: {    
			// 通過跳轉一個空頁面再返回的方式來實現刷新當前頁面數據的目的
			onRefresh () {      
				this.$router.replace('/refresh')    
			}  
		}
	}
</script>
這是app.vue,這裡簡單演示一下斷網。在http.js中介紹了,我們會在斷網的時候,來更新vue中network的狀態,那麼這裡我們根據network的狀態來判斷是否需要載入這個斷網組件。斷網情況下,載入斷網組件,不載入對應頁面的組件。當點擊刷新的時候,我們通過跳轉refesh頁面然後立即返回的方式來實現重新獲取數據的操作。因此我們需要新建一個refresh.vue頁面,併在其beforeRouteEnter鉤子中再返回當前頁面。


// refresh.vue
beforeRouteEnter (to, from, next) {
	next(vm => {            
		vm.$router.replace(from.fullPath)        
	})    
}

"""


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 新建axiosj.ts import axios from 'axios'; import { showMessage } from "./status"; // 引入狀態碼文件 import { ElMessage } from 'element-plus' // 引入el 提示框,這個項目里用什 ...
  • TLDR vscode的GraphQL語法插件, 目前比較推薦Graphql Foundation的GraphQL: Language Feature Support 相關配置, 見[GraphQL: Language Feature Support](# GraphQL: Language Fea ...
  • ![](https://img2023.cnblogs.com/blog/3076680/202307/3076680-20230713135333820-1976638091.png) # 1. 互連層是可以真正構建高可用性的地方 ## 1.1. 流量管理 ## 1.2. 負載均衡 ## 1.3. ...
  • 1、導入 關於Win32的錯誤認知: (1)已經有malloc()函數了,為什麼還要學Win32 API? (2)學MFC就可以了,為什麼要學Win32? Win32課程包含的內容: 01、字元 09、文件系統 02、多線程 10、記憶體映射 03、線程同步 11、DLL 04、視窗的本質 12、遠程 ...
  • 一、jupyter notebook介紹 1、簡介 Jupyter Notebook是基於網頁的用於交互計算的應用程式。其可被應用於全過程計算:開發、文檔編寫、運行代碼和展示結果。——Jupyter Notebook官方介紹 簡而言之,Jupyter Notebook是以網頁的形式打開,可以在網頁頁 ...
  • # java操作zookeeper 1. 創建一個maven項目在pom文件里引入如下依賴: ~~~XML junit junit 4.10 test org.apache.curator curator-framework 4.0.0 org.apache.curator curator-reci ...
  • # 尾碼數組是什麼 尾碼數組就是主要處理字元串尾碼問題的,它的實現演算法主要有兩種:倍增法和 DC3,複雜度分別是 $O(n\log n)$ 和 $O(n)$。這裡由於 DC3 代碼答辯且難以理解,我就只寫了倍增法的實現。 # 例題引入 [P3809 【模板】尾碼排序](https://www.luo ...
  • > 出於各種限制,很多公司依然停留在Java8,部分小伙伴轉向了Kotlin。Kotlin作為靜態編譯語言,提供大量語法糖,而且編譯後的位元組碼跟Java一致。 > > 當時,Java8於2014年發佈,Kotlin於2016年,很多宣稱的語法糖都是對比的Java8。不禁要問,相對今天的Java17, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...