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