vue項目中axios的封裝請求
一、簡介
axios 是一個輕量的HTTP客戶端,它基于 XMLHttpRequest
服務來執(zhí)行 HTTP 請求,支持豐富的配置,支持 Promise,支持瀏覽器端和 Node.js 端。自Vue2.0起,尤大大宣布取消對vue-resource
的官方推薦,轉而推薦 axios?,F(xiàn)在 axios 已經(jīng)成為大部分 Vue 開發(fā)者的首選。( 如果你還不熟悉 axios,可以在這里查看它的API。)
封裝前,先來看下,不封裝的情況下,一個實際項目中axios請求的樣子。
大概是長這樣:
axios('http://localhost:3000/data', { ? method: 'GET', ? timeout: 1000, ? withCredentials: true, ? headers: { ? ? 'Content-Type': 'application/json', ? ? Authorization: 'xxx', ? }, ? transformRequest: [function (data, headers) { ? ? return data; ? }], ? // 其他請求配置... }) .then((data) => { ? // todo: 真正業(yè)務邏輯代碼 ? console.log(data); }, (err) => { ? if (err.response.status === 401) { ? // handle authorization error ? } ? if (err.response.status === 403) { ? // handle server forbidden error ? } ? // 其他錯誤處理..... ? console.log(err); });
可以看到在這段代碼中,頁面代碼邏輯只在第15行處,上方的一大塊請求配置代碼和下方一大塊響應錯誤處理代碼,幾乎跟頁面功能沒有關系,而且每個請求中這些內(nèi)容都差不多,甚至有的部分完全一樣。
二、封裝后
1.封裝步驟
封裝的本質就是在待封裝的內(nèi)容外面添加各種東西,然后把它們作為一個新的整體呈現(xiàn)給使用者,以達到擴展和易用的目的。
封裝 axios
要做的事情,就是把所有HTTP請求共用的配置,事先都在axios上配置好,預留好必要的參數(shù)和接口,然后把它作為新的axios返回。
目錄結構如下(由Vue-cli 3.0 生成):
|--public/
|--mock/
| |--db.json # 我新建的接口模擬數(shù)據(jù)
|--src/
| |--assets/
| |--components/
| |--router/
| |--store/
| |--views/
| |--Home.Vue
| |--App.vue
| |--main.js
| |--theme.styl
|--package.json
|...
2.封裝目標
在 Home 頁,發(fā)起 axios 請求時就像調用一個只有少量參數(shù)的方法一樣簡單,這樣我就可以專注業(yè)務代碼了。
1. 將 axios 封裝到一個獨立的文件
- 在src下創(chuàng)建 utils/http.js 文件
? cd src ? mkdir utils ? touch http.js
- 引入 axios
? // src/utils/http.js ? import axios from 'axios';
- 創(chuàng)建一個類
? //src/utils/http.js ? //... ? class NewAxios { ?? ? }
- 給不同環(huán)境配置不同請求地址
根據(jù)process.env.NODE_ENV
配置不同的 baseURL
,使項目只需執(zhí)行相應打包命令,就可以在不同環(huán)境中自動切換請求主機地址。
// src/utils/http.js //... const getBaseUrl = (env) => { ? let base = { ? ? production: '/', ? ? development: 'http://localhost:3000', ? ? test: 'http://localhost:3001', ? }[env]; ? if (!base) { ? ? base = '/'; ? } ? return base; }; class NewAxios { ? constructor() { ? ? this.baseURL = getBaseUrl(process.env.NODE_ENV); ? } }
- 配置超時時間
timeout
屬性,我一般設置10秒。
// src/utils/http.js //... class NewAxios { ? constructor() { ? ? //... ? ? this.timeout = 10000; ? } }
- 配置允許攜帶憑證
widthCredentials
屬性設為true
// src/utils/http.js //... class NewAxios { ? constructor() { ? ? //... ? ? this.withCredentials = true; ? } }
- 給這個類創(chuàng)建實例上的方法request
在 request
方法里,創(chuàng)建新的axios實例,接收請求配置參數(shù),處理參數(shù),添加配置,返回axios實例的請求結果(一個promise對象)。
你也可以不創(chuàng)建,直接使用默認導出的axios實例,然后把所有配置都放到它上面,不過這樣一來整個項目就會共用一個axios實例。雖然大部分項目下這樣夠用沒問題,但是有的項目中不同服務地址的請求和響應結構可能完全不同,這個時候共用一個實例就沒辦法支持了。所以為了封裝可以更通用,更具靈活性,我會使用axios
的create
方法,使每次發(fā)請求都是新的axios實例。
// src/utils/http.js //... class NewAxios { ? //... ? request(options) { ? ? // 每次請求都會創(chuàng)建新的axios實例。 ? ? const instance = axios.create(); ? ? const config = { // 將用戶傳過來的參數(shù)與公共配置合并。 ? ? ? ...options, ? ? ? baseURL: this.baseURL, ? ? ? timeout: this.timeout, ? ? ? withCredentials: this.withCredentials, ? ? }; ? ? // 配置攔截器,支持根據(jù)不同url配置不同的攔截器。 ? ? this.setInterceptors(instance, options.url); ? ? return instance(config); // 返回axios實例的執(zhí)行結果 ? } }
因為攔截器配置內(nèi)容比較多,所以封裝成一個內(nèi)部函數(shù)了。
- 配置請求攔截器
在發(fā)送請求前對請求參數(shù)做的所有修改都在這里統(tǒng)一配置。比如統(tǒng)一添加token憑證、統(tǒng)一設置語言、統(tǒng)一設置內(nèi)容類型、指定數(shù)據(jù)格式等等。做完后記得返回這個配置,否則整個請求不會進行。
我這里就配置一個token
。
// src/utils/http.js //... class NewAxios { ? //... ? // 這里的url可供你針對需要特殊處理的接口路徑設置不同攔截器。 ? setInterceptors = (instance, url) => {? ? ? instance.interceptors.request.use((config) => { // 請求攔截器 ? ? ? // 配置token ? ? ? config.headers.AuthorizationToken = localStorage.getItem('AuthorizationToken') || ''; ? ? ? return config; ? ? }, err => Promise.reject(err)); ? } ? //... }
- 配置響應攔截器
在請求的then
或catch
處理前對響應數(shù)據(jù)進行一輪預先處理。比如過濾響應數(shù)據(jù),更多的,是在這里對各種響應錯誤碼進行統(tǒng)一錯誤處理,還有斷網(wǎng)處理等等。
我這里就判斷一下403和斷網(wǎng)。
// src/utils/http.js //... class NewAxios { ? //... ? setInterceptors = (instance, url) => { ? ? //... ? ? instance.interceptors.response.use((response) => { // 響應攔截器 ? ? ? // todo: 想根據(jù)業(yè)務需要,對響應結果預先處理的,都放在這里 ? ? ? console.log(); ? ? ? return response; ? ? }, (err) => { ? ? ? if (err.response) { // 響應錯誤碼處理 ? ? ? ? switch (err.response.status) { ? ? ? ? ? case '403': ? ? ? ? ? ? // todo: handler server forbidden error ? ? ? ? ? ? break; ? ? ? ? ? ? // todo: handler other status code ? ? ? ? ? default: ? ? ? ? ? ? break; ? ? ? ? } ? ? ? ? return Promise.reject(err.response); ? ? ? } ? ? ? if (!window.navigator.online) { // 斷網(wǎng)處理 ? ? ? ? // todo: jump to offline page ? ? ? ? return -1; ? ? ? } ? ? ? return Promise.reject(err); ? ? }); ? } ? //... }
另外,在攔截器里,還適合放置loading等緩沖效果:在請求攔截器里顯示loading,在響應攔截器里移除loading。這樣所有請求就都有了一個統(tǒng)一的loading
效果。
- 默認導出新的實例
? // src/utils/http.js ?? ? //... ? export default new NewAxios();
最后完整的代碼如下:
// src/utils/http.js import axios from 'axios'; const getBaseUrl = (env) => { ? let base = { ? ? production: '/', ? ? development: 'http://localhost:3000', ? ? test: 'http://localhost:3001', ? }[env]; ? if (!base) { ? ? base = '/'; ? } ? return base; }; class NewAxios { ? constructor() { ? ? this.baseURL = getBaseUrl(process.env.NODE_ENV); ? ? this.timeout = 10000; ? ? this.withCredentials = true; ? } ? // 這里的url可供你針對需要特殊處理的接口路徑設置不同攔截器。 ? setInterceptors = (instance, url) => { ? ? instance.interceptors.request.use((config) => { ? ? ? // 在這里添加loading ? ? ? // 配置token ? ? ? config.headers.AuthorizationToken = localStorage.getItem('AuthorizationToken') || ''; ? ? ? return config; ? ? }, err => Promise.reject(err)); ? ? instance.interceptors.response.use((response) => { ? ? ? // 在這里移除loading ? ? ? // todo: 想根據(jù)業(yè)務需要,對響應結果預先處理的,都放在這里 ? ? ? return response; ? ? }, (err) => { ? ? ? if (err.response) { // 響應錯誤碼處理 ? ? ? ? switch (err.response.status) { ? ? ? ? ? case '403': ? ? ? ? ? ? // todo: handler server forbidden error ? ? ? ? ? ? break; ? ? ? ? ? ? // todo: handler other status code ? ? ? ? ? default: ? ? ? ? ? ? break; ? ? ? ? } ? ? ? ? return Promise.reject(err.response); ? ? ? } ? ? ? if (!window.navigator.online) { // 斷網(wǎng)處理 ? ? ? ? // todo: jump to offline page ? ? ? ? return -1; ? ? ? } ? ? ? return Promise.reject(err); ? ? }); ? } ? request(options) { ? ? // 每次請求都會創(chuàng)建新的axios實例。 ? ? const instance = axios.create(); ? ? const config = { // 將用戶傳過來的參數(shù)與公共配置合并。 ? ? ? ...options, ? ? ? baseURL: this.baseURL, ? ? ? timeout: this.timeout, ? ? ? withCredentials: this.withCredentials, ? ? }; ? ? // 配置攔截器,支持根據(jù)不同url配置不同的攔截器。 ? ? this.setInterceptors(instance, options.url); ? ? return instance(config); // 返回axios實例的執(zhí)行結果 ? } } export default new NewAxios();
現(xiàn)在 axios
封裝算是完成了80%。我們還需要再進一步把axios和接口結合再封裝一層,才能達到我在一開始定的封裝目標。
3. 使用新的 axios 封裝API
- 在 src 目錄下新建 api 文件夾。把所有涉及HTTP請求的接口統(tǒng)一集中到這個目錄來管理。
- 新建
home.js
。我們需要把接口根據(jù)一定規(guī)則分好類,一類接口對應一個js文件。這個分類可以是按頁面來劃分,或者按模塊等等。為了演示更直觀,我這里就按頁面來劃分了。實際根據(jù)自己的需求來定。 - 使用新的 axios 封裝API(固定url的值,合并用戶傳過來的參數(shù)),然后命名導出這些函數(shù)。
// src/api/home.js? import axios from '@/utils/http'; export const fetchData = options => axios.request({ ? ...options, ? url: '/data', }); export default {};
在 api 目錄下新建 index.js,把其他文件的接口都在這個文件里匯總導出。
// src/api/index.js ?? ? export * from './home';
這層封裝將我們的新的axios封裝到了更簡潔更語義化的接口方法中。
現(xiàn)在我們的目錄結構長這樣:
|--public/
|--mock/
| |--db.json # 接口模擬數(shù)據(jù)
|--src/
| |--api/ # 所有的接口都集中在這個目錄下
| |--home.js # Home頁面里涉及到的接口封裝在這里
| |--index.js # 項目中所有接口調用的入口
| |--assets/
| |--components/
| |--router/
| |--store/
| |--utils/
| |--http.js # axios封裝在這里
| |--views/
| |--Home.Vue
| |--App.vue
| |--main.js
| |--theme.styl
|--package.json
|...
4.使用封裝后的axios
現(xiàn)在我們要發(fā)HTTP請求時,只需引入 api 下的 index.js 文件就可以調用任何接口了,并且用的是封裝后的 axios。
// src/views/Home.vue <template> ? <div class="home"> ? ? <h1>This is home page</h1> ? </div> </template> <script> // @ is an alias to /src import { fetchData } from '@/api/index'; export default { ? name: 'home', ? mounted() { ? ? fetchData() ?// axios請求在這里 ? ? ? .then((data) => { ? ? ? ? console.log(data); ? ? ? }) ? ? ? .catch((err) => { ? ? ? ? console.log(err); ? ? ? }); ? }, }; </script>
axios請求被封裝在fetchData函數(shù)里,頁面請求壓根不需要出現(xiàn)任何axios API,悄無聲息地發(fā)起請求獲取響應,就像在調用一個簡單的 Promise 函數(shù)一樣輕松。并且在頁面中只需專注處理業(yè)務功能,不用被其他事物干擾。
到此這篇關于vue項目中axios的封裝請求的文章就介紹到這了,更多相關vue中axios封裝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Vue中v-if、v-if-else、v-else-if與v-show的基本使用
v-if,v-else,v-else-if,v-if指令用于條件性地渲染一塊內(nèi)容,這塊內(nèi)容只會在指令的表達式返回truth值的時候被渲染,這篇文章主要給大家介紹了關于Vue中v-if、v-if-else、v-else-if與v-show的基本使用,需要的朋友可以參考下2022-10-10vue2.6.10+vite2開啟template模板動態(tài)編譯的過程
這篇文章主要介紹了vue2.6.10+vite2開啟template模板動態(tài)編譯,本文結合實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-02-02