vue項(xiàng)目中axios的封裝請(qǐng)求
一、簡(jiǎn)介
axios 是一個(gè)輕量的HTTP客戶端,它基于 XMLHttpRequest
服務(wù)來(lái)執(zhí)行 HTTP 請(qǐng)求,支持豐富的配置,支持 Promise,支持瀏覽器端和 Node.js 端。自Vue2.0起,尤大大宣布取消對(duì)vue-resource
的官方推薦,轉(zhuǎn)而推薦 axios。現(xiàn)在 axios 已經(jīng)成為大部分 Vue 開(kāi)發(fā)者的首選。( 如果你還不熟悉 axios,可以在這里查看它的API。)
封裝前,先來(lái)看下,不封裝的情況下,一個(gè)實(shí)際項(xiàng)目中axios請(qǐng)求的樣子。
大概是長(zhǎng)這樣:
axios('http://localhost:3000/data', { ? method: 'GET', ? timeout: 1000, ? withCredentials: true, ? headers: { ? ? 'Content-Type': 'application/json', ? ? Authorization: 'xxx', ? }, ? transformRequest: [function (data, headers) { ? ? return data; ? }], ? // 其他請(qǐng)求配置... }) .then((data) => { ? // todo: 真正業(yè)務(wù)邏輯代碼 ? console.log(data); }, (err) => { ? if (err.response.status === 401) { ? // handle authorization error ? } ? if (err.response.status === 403) { ? // handle server forbidden error ? } ? // 其他錯(cuò)誤處理..... ? console.log(err); });
可以看到在這段代碼中,頁(yè)面代碼邏輯只在第15行處,上方的一大塊請(qǐng)求配置代碼和下方一大塊響應(yīng)錯(cuò)誤處理代碼,幾乎跟頁(yè)面功能沒(méi)有關(guān)系,而且每個(gè)請(qǐng)求中這些內(nèi)容都差不多,甚至有的部分完全一樣。
二、封裝后
1.封裝步驟
封裝的本質(zhì)就是在待封裝的內(nèi)容外面添加各種東西,然后把它們作為一個(gè)新的整體呈現(xiàn)給使用者,以達(dá)到擴(kuò)展和易用的目的。
封裝 axios
要做的事情,就是把所有HTTP請(qǐng)求共用的配置,事先都在axios上配置好,預(yù)留好必要的參數(shù)和接口,然后把它作為新的axios返回。
目錄結(jié)構(gòu)如下(由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.封裝目標(biāo)
在 Home 頁(yè),發(fā)起 axios 請(qǐng)求時(shí)就像調(diào)用一個(gè)只有少量參數(shù)的方法一樣簡(jiǎn)單,這樣我就可以專注業(yè)務(wù)代碼了。
1. 將 axios 封裝到一個(gè)獨(dú)立的文件
- 在src下創(chuàng)建 utils/http.js 文件
? cd src ? mkdir utils ? touch http.js
- 引入 axios
? // src/utils/http.js ? import axios from 'axios';
- 創(chuàng)建一個(gè)類
? //src/utils/http.js ? //... ? class NewAxios { ?? ? }
- 給不同環(huán)境配置不同請(qǐng)求地址
根據(jù)process.env.NODE_ENV
配置不同的 baseURL
,使項(xiàng)目只需執(zhí)行相應(yīng)打包命令,就可以在不同環(huán)境中自動(dòng)切換請(qǐng)求主機(jī)地址。
// 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); ? } }
- 配置超時(shí)時(shí)間
timeout
屬性,我一般設(shè)置10秒。
// src/utils/http.js //... class NewAxios { ? constructor() { ? ? //... ? ? this.timeout = 10000; ? } }
- 配置允許攜帶憑證
widthCredentials
屬性設(shè)為true
// src/utils/http.js //... class NewAxios { ? constructor() { ? ? //... ? ? this.withCredentials = true; ? } }
- 給這個(gè)類創(chuàng)建實(shí)例上的方法request
在 request
方法里,創(chuàng)建新的axios實(shí)例,接收請(qǐng)求配置參數(shù),處理參數(shù),添加配置,返回axios實(shí)例的請(qǐng)求結(jié)果(一個(gè)promise對(duì)象)。
你也可以不創(chuàng)建,直接使用默認(rèn)導(dǎo)出的axios實(shí)例,然后把所有配置都放到它上面,不過(guò)這樣一來(lái)整個(gè)項(xiàng)目就會(huì)共用一個(gè)axios實(shí)例。雖然大部分項(xiàng)目下這樣夠用沒(méi)問(wèn)題,但是有的項(xiàng)目中不同服務(wù)地址的請(qǐng)求和響應(yīng)結(jié)構(gòu)可能完全不同,這個(gè)時(shí)候共用一個(gè)實(shí)例就沒(méi)辦法支持了。所以為了封裝可以更通用,更具靈活性,我會(huì)使用axios
的create
方法,使每次發(fā)請(qǐng)求都是新的axios實(shí)例。
// src/utils/http.js //... class NewAxios { ? //... ? request(options) { ? ? // 每次請(qǐng)求都會(huì)創(chuàng)建新的axios實(shí)例。 ? ? const instance = axios.create(); ? ? const config = { // 將用戶傳過(guò)來(lái)的參數(shù)與公共配置合并。 ? ? ? ...options, ? ? ? baseURL: this.baseURL, ? ? ? timeout: this.timeout, ? ? ? withCredentials: this.withCredentials, ? ? }; ? ? // 配置攔截器,支持根據(jù)不同url配置不同的攔截器。 ? ? this.setInterceptors(instance, options.url); ? ? return instance(config); // 返回axios實(shí)例的執(zhí)行結(jié)果 ? } }
因?yàn)閿r截器配置內(nèi)容比較多,所以封裝成一個(gè)內(nèi)部函數(shù)了。
- 配置請(qǐng)求攔截器
在發(fā)送請(qǐng)求前對(duì)請(qǐng)求參數(shù)做的所有修改都在這里統(tǒng)一配置。比如統(tǒng)一添加token憑證、統(tǒng)一設(shè)置語(yǔ)言、統(tǒng)一設(shè)置內(nèi)容類型、指定數(shù)據(jù)格式等等。做完后記得返回這個(gè)配置,否則整個(gè)請(qǐng)求不會(huì)進(jìn)行。
我這里就配置一個(gè)token
。
// src/utils/http.js //... class NewAxios { ? //... ? // 這里的url可供你針對(duì)需要特殊處理的接口路徑設(shè)置不同攔截器。 ? setInterceptors = (instance, url) => {? ? ? instance.interceptors.request.use((config) => { // 請(qǐng)求攔截器 ? ? ? // 配置token ? ? ? config.headers.AuthorizationToken = localStorage.getItem('AuthorizationToken') || ''; ? ? ? return config; ? ? }, err => Promise.reject(err)); ? } ? //... }
- 配置響應(yīng)攔截器
在請(qǐng)求的then
或catch
處理前對(duì)響應(yīng)數(shù)據(jù)進(jìn)行一輪預(yù)先處理。比如過(guò)濾響應(yīng)數(shù)據(jù),更多的,是在這里對(duì)各種響應(yīng)錯(cuò)誤碼進(jìn)行統(tǒng)一錯(cuò)誤處理,還有斷網(wǎng)處理等等。
我這里就判斷一下403和斷網(wǎng)。
// src/utils/http.js //... class NewAxios { ? //... ? setInterceptors = (instance, url) => { ? ? //... ? ? instance.interceptors.response.use((response) => { // 響應(yīng)攔截器 ? ? ? // todo: 想根據(jù)業(yè)務(wù)需要,對(duì)響應(yīng)結(jié)果預(yù)先處理的,都放在這里 ? ? ? console.log(); ? ? ? return response; ? ? }, (err) => { ? ? ? if (err.response) { // 響應(yīng)錯(cuò)誤碼處理 ? ? ? ? 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等緩沖效果:在請(qǐng)求攔截器里顯示loading,在響應(yīng)攔截器里移除loading。這樣所有請(qǐng)求就都有了一個(gè)統(tǒng)一的loading
效果。
- 默認(rèn)導(dǎo)出新的實(shí)例
? // 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可供你針對(duì)需要特殊處理的接口路徑設(shè)置不同攔截器。 ? 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è)務(wù)需要,對(duì)響應(yīng)結(jié)果預(yù)先處理的,都放在這里 ? ? ? return response; ? ? }, (err) => { ? ? ? if (err.response) { // 響應(yīng)錯(cuò)誤碼處理 ? ? ? ? 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) { ? ? // 每次請(qǐng)求都會(huì)創(chuàng)建新的axios實(shí)例。 ? ? const instance = axios.create(); ? ? const config = { // 將用戶傳過(guò)來(lái)的參數(shù)與公共配置合并。 ? ? ? ...options, ? ? ? baseURL: this.baseURL, ? ? ? timeout: this.timeout, ? ? ? withCredentials: this.withCredentials, ? ? }; ? ? // 配置攔截器,支持根據(jù)不同url配置不同的攔截器。 ? ? this.setInterceptors(instance, options.url); ? ? return instance(config); // 返回axios實(shí)例的執(zhí)行結(jié)果 ? } } export default new NewAxios();
現(xiàn)在 axios
封裝算是完成了80%。我們還需要再進(jìn)一步把a(bǔ)xios和接口結(jié)合再封裝一層,才能達(dá)到我在一開(kāi)始定的封裝目標(biāo)。
3. 使用新的 axios 封裝API
- 在 src 目錄下新建 api 文件夾。把所有涉及HTTP請(qǐng)求的接口統(tǒng)一集中到這個(gè)目錄來(lái)管理。
- 新建
home.js
。我們需要把接口根據(jù)一定規(guī)則分好類,一類接口對(duì)應(yīng)一個(gè)js文件。這個(gè)分類可以是按頁(yè)面來(lái)劃分,或者按模塊等等。為了演示更直觀,我這里就按頁(yè)面來(lái)劃分了。實(shí)際根據(jù)自己的需求來(lái)定。 - 使用新的 axios 封裝API(固定url的值,合并用戶傳過(guò)來(lái)的參數(shù)),然后命名導(dǎo)出這些函數(shù)。
// src/api/home.js? import axios from '@/utils/http'; export const fetchData = options => axios.request({ ? ...options, ? url: '/data', }); export default {};
在 api 目錄下新建 index.js,把其他文件的接口都在這個(gè)文件里匯總導(dǎo)出。
// src/api/index.js ?? ? export * from './home';
這層封裝將我們的新的axios封裝到了更簡(jiǎn)潔更語(yǔ)義化的接口方法中。
現(xiàn)在我們的目錄結(jié)構(gòu)長(zhǎng)這樣:
|--public/
|--mock/
| |--db.json # 接口模擬數(shù)據(jù)
|--src/
| |--api/ # 所有的接口都集中在這個(gè)目錄下
| |--home.js # Home頁(yè)面里涉及到的接口封裝在這里
| |--index.js # 項(xiàng)目中所有接口調(diào)用的入口
| |--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請(qǐng)求時(shí),只需引入 api 下的 index.js 文件就可以調(diào)用任何接口了,并且用的是封裝后的 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請(qǐng)求在這里 ? ? ? .then((data) => { ? ? ? ? console.log(data); ? ? ? }) ? ? ? .catch((err) => { ? ? ? ? console.log(err); ? ? ? }); ? }, }; </script>
axios請(qǐng)求被封裝在fetchData函數(shù)里,頁(yè)面請(qǐng)求壓根不需要出現(xiàn)任何axios API,悄無(wú)聲息地發(fā)起請(qǐng)求獲取響應(yīng),就像在調(diào)用一個(gè)簡(jiǎn)單的 Promise 函數(shù)一樣輕松。并且在頁(yè)面中只需專注處理業(yè)務(wù)功能,不用被其他事物干擾。
到此這篇關(guān)于vue項(xiàng)目中axios的封裝請(qǐng)求的文章就介紹到這了,更多相關(guān)vue中axios封裝內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue echarts畫(huà)甘特圖流程詳細(xì)講解
這篇文章主要介紹了Vue echarts畫(huà)甘特圖流程,甘特圖(Gantt chart)又稱為橫道圖、條狀圖(Bar chart)。其通過(guò)條狀圖來(lái)顯示項(xiàng)目、進(jìn)度和其他時(shí)間相關(guān)的系統(tǒng)進(jìn)展的內(nèi)在關(guān)系隨著時(shí)間進(jìn)展的情況2022-09-09Vue中v-if、v-if-else、v-else-if與v-show的基本使用
v-if,v-else,v-else-if,v-if指令用于條件性地渲染一塊內(nèi)容,這塊內(nèi)容只會(huì)在指令的表達(dá)式返回truth值的時(shí)候被渲染,這篇文章主要給大家介紹了關(guān)于Vue中v-if、v-if-else、v-else-if與v-show的基本使用,需要的朋友可以參考下2022-10-10手寫(xiě)vue無(wú)限滾動(dòng)指令的詳細(xì)過(guò)程
今天在移動(dòng)端項(xiàng)目中遇見(jiàn)一個(gè)需求,需要數(shù)據(jù)無(wú)限滾動(dòng),所以下面這篇文章主要給大家介紹了關(guān)于手寫(xiě)vue無(wú)限滾動(dòng)指令的詳細(xì)過(guò)程,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09Vue?element?ui用戶展示頁(yè)面的實(shí)例
這篇文章主要介紹了Vue?element?ui用戶展示頁(yè)面的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05vue2.6.10+vite2開(kāi)啟template模板動(dòng)態(tài)編譯的過(guò)程
這篇文章主要介紹了vue2.6.10+vite2開(kāi)啟template模板動(dòng)態(tài)編譯,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-02-02vue實(shí)現(xiàn)廣告欄上下滾動(dòng)效果
這篇文章主要介紹了vue實(shí)現(xiàn)廣告欄上下滾動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11vue配置請(qǐng)求本地json數(shù)據(jù)的方法
這篇文章主要介紹了vue配置請(qǐng)求本地json數(shù)據(jù)的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04Vue使用vue-pdf實(shí)現(xiàn)PDF文件預(yù)覽
這篇文章主要為大家詳細(xì)介紹了Vue如何使用vue-pdf實(shí)現(xiàn)PDF文件預(yù)覽的功能,文中的示例代碼講解詳細(xì),具有一定的參考價(jià)值,感興趣的可以了解一下2023-03-03