0. 系列文章
1.使用Typescript重構axios(一)——寫在最前面
2.使用Typescript重構axios(二)——項目起手,跑通流程
3.使用Typescript重構axios(三)——實現基礎功能:處理get請求url參數
4.使用Typescript重構axios(四)——實現基礎功能:處理post請求參數
5.使用Typescript重構axios(五)——實現基礎功能:處理請求的header
6.使用Typescript重構axios(六)——實現基礎功能:獲取響應數據
7.使用Typescript重構axios(七)——實現基礎功能:處理響應header
8.使用Typescript重構axios(八)——實現基礎功能:處理響應data
9.使用Typescript重構axios(九)——異常處理:基礎版
10.使用Typescript重構axios(十)——異常處理:增強版
11.使用Typescript重構axios(十一)——接口擴展
12.使用Typescript重構axios(十二)——增加參數
13.使用Typescript重構axios(十三)——讓響應數據支持泛型
14.使用Typescript重構axios(十四)——實現攔截器
15.使用Typescript重構axios(十五)——默認配置
16.使用Typescript重構axios(十六)——請求和響應數據配置化
17.使用Typescript重構axios(十七)——增加axios.create
18.使用Typescript重構axios(十八)——請求取消功能:總體思路
19.使用Typescript重構axios(十九)——請求取消功能:實現第二種使用方式
20.使用Typescript重構axios(二十)——請求取消功能:實現第一種使用方式
21.使用Typescript重構axios(二十一)——請求取消功能:添加axios.isCancel接口
22.使用Typescript重構axios(二十二)——請求取消功能:收尾
23.使用Typescript重構axios(二十三)——添加withCredentials屬性
24.使用Typescript重構axios(二十四)——防御XSRF攻擊
25.使用Typescript重構axios(二十五)——文件上傳下載進度監控
26.使用Typescript重構axios(二十六)——添加HTTP授權auth屬性
27.使用Typescript重構axios(二十七)——添加請求狀態碼合法性校驗
28.使用Typescript重構axios(二十八)——自定義序列化請求參數
29.使用Typescript重構axios(二十九)——添加baseURL
30.使用Typescript重構axios(三十)——添加axios.getUri方法
31.使用Typescript重構axios(三十一)——添加axios.all和axios.spread方法
32.使用Typescript重構axios(三十二)——寫在最后面(總結)
1. 前言
在實際工作項目中,服務端所有的api
接口都會部署在同一個域名下,例如豆瓣電影的api
接口都統一部署在https://api.douban.com
下面,當我們想要獲取正在熱映的電影列表時可以請求https://api.douban.com/v2/movie/in_theaters
;當想要獲取TOP250
電影列表時可以請求https://api.douban.com/v2/movie/top250
等等。細心的你肯定會看到每個電影接口的前綴https://api.douban.com/v2/movie/
都是相同的,只是后面的類別不同。本着能少些一行代碼就少一寫一行的原則,有沒有什么辦法只需把前綴寫一次,每次請求的時候只用帶上后面的類別后綴即可。答案當然是有的。
官方axios
在請求配置對象中為我們提供了baseURL
屬性,官方文檔對該屬性介紹如下:
// `baseURL` will be prepended to `url` unless `url` is absolute.
// It can be convenient to set `baseURL` for an instance of axios to pass relative URLs
// to methods of that instance.
baseURL: 'https://some-domain.com/api/',
當配置了baseURL
屬性,它就會和之后請求傳入的 url
拼接成完整的絕對地址,除非請求傳入的 url
已經是絕對地址。為axios
實例設置baseURL
可以方便地將相對url
傳遞給該實例的方法。
說了這么多,其實就是想表達如下意思:
const instance = axios.create({
baseURL: 'https://api.douban.com/v2/movie/'
})
instance.get('/in_theaters') // 獲取正在熱映的電影列表
instance.post('/top250') // 獲取`TOP250`電影列表
那么接下來,我們就為我們的axios
添加baseURL
屬性以及相關功能。
2. 思路分析
實現之前,我們先來理一下思路:
官方文檔說:當配置了baseURL
屬性,它就會和之后請求傳入的 url
拼接成完整的絕對地址,除非請求傳入的 url
已經是絕對地址。
那么當用戶配置了baseURL
屬性時:
- 首先,判斷傳入的
url
是否是絕對地址,如果是,則不用和baseURL
拼接; - 如果不是,則將
baseURL
與傳入的url
進行拼接; - 拼接好之后,將拼接后的
url
作為請求真正的url
發送請求;
OK,以上就是實現思路,接下來,我們就逐步實現它。
3. 向請求配置對象添加屬性
向請求配置對象config
中添加 baseURL
屬性之前,我們需要先在src/types/index.ts
中的配置對象的接口類型定義AxiosRequestConfig
上添加該屬性的定義,如下:
export interface AxiosRequestConfig {
// 新增
baseURL?: string;
}
4. 判斷傳入的url是否為絕對地址
首先,我們先來編寫一個輔助函數 isAbsoluteURL
,用來判斷傳入的url
是否為絕對地址,我們在src/helpers
目錄下創建isAbsoluteURL.ts
文件,在該文件中編寫該函數,如下:
export default function isAbsoluteURL(url: string): boolean {
// 如果URL以“<scheme>://”或“//”(協議相對URL)開頭,則該URL被視為絕對值。
// RFC 3986將方案名稱定義為以字母開頭的字符序列,
// 后跟字母,數字,加號,句點或連字符的任意組合。
return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(url);
}
該函數很簡單,就是編寫一個絕對地址的正則表達式,如果傳入的url
匹配該正則,則表明它是絕對地址,反之則不是。
5. 拼接url
如果傳入的url
不是絕對地址的話,我們就需要將baseURL
與傳入的url
進行拼接,所以我們再編寫一個拼接的輔助函數combineURLs
,該函數用來將baseURL
與傳入的url
進行拼接,將拼接后的結果返回。我們在src/helpers
目錄下創建combineURLs.ts
文件,在該文件中編寫該函數,如下:
export default function combineURLs(
baseURL: string,
relativeURL?: string
): string {
return relativeURL
? baseURL.replace(/\/+$/, "") + "/" + relativeURL.replace(/^\/+/, "")
: baseURL;
}
在該函數中,為了統一起見,無論baseURL
最后有沒有/
,都將其去掉,並且不管傳入的url
前面有沒有/
,也都將其去掉,最后用/
將兩部分連接。
OK,所有的輔助函數都實現好之后,我們就要在src/core/dispatchRequest.ts
文件中的transformUrl
函數中編寫相關邏輯使用這兩個輔助函數。
6. 修改transformUrl函數邏輯
按照第2章的思路分析,先判斷傳入的url
是否是絕對地址,如果不是,則將baseURL
與傳入的url
進行拼接;拼接好之后,將拼接后的url
作為請求真正的url
發送請求;如下:
function transformUrl(config: AxiosRequestConfig): string {
let { url, params, paramsSerializer, baseURL } = config;
if (baseURL && !isAbsoluteURL(url!)) {
url = combineURLs(baseURL, url);
}
return bulidURL(url!, params, paramsSerializer);
}
OK,baseURL
屬性以及相關邏輯就處理好了,接下來,我們就編寫demo
來測試下效果如何。
7. demo編寫
在 examples
目錄下創建 baseURL
目錄,在 baseURL
目錄下創建 index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>baseURL demo</title>
</head>
<body>
<script src="/__build__/baseURL.js"></script>
</body>
</html>
接着再創建 app.ts
作為入口文件:
import axios from "../../src/axios";
const instance = axios.create({
baseURL: 'http://192.168.1.106:3000/'
})
instance.get('/api/baseURL')
instance.get('http://192.168.1.106:3000/api/baseURL')
在本demo
中,我們編寫了兩個請求,第一個請求用的是相對url
,它會將baseURL
與其拼接;而第二個請求時絕對url
,不會再去拼接 baseURL
。
接着在 server/server.js
添加新的接口路由:
// 添加baseURL屬性
router.get("/api/baseURL", function(req, res) {
res.end();
});
最后在根目錄下的index.html
中加上啟動該demo
的入口:
<li><a href="examples/baseURL">baseURL</a></li>
OK,我們在命令行中執行:
# 同時開啟客戶端和服務端
npm run server | npm start
接着我們打開 chrome
瀏覽器,訪問 http://localhost:8000/ 即可訪問我們的 demo
了,我們點擊 baseURL
,就可以看到兩個請求都已經正常發出,並且打開F12
中的network
可以看到:第一個請求的url
是通過baseURL
與傳入的url
拼接后的結果,而第二個請求的url
是原始傳入的url
,沒有被拼接。
OK,以上就是為我們的axios
添加baseURL
屬性,並實現了其功能。
(完)