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. 前言
有時候我們在頁面中往往會讓用戶上傳或下載某個東西,當用戶點擊了上傳或下載按鈕,頁面隨即開始進行相關操作,此時用戶便處於等待狀態,即等待上傳完成或下載完成,一般來說,這里通常會加一個loading
圖,提示用戶“文件正在上傳/下載中。。。”,這樣雖然一定程度上優化了一點用戶體驗,但是用戶還處於漫無目的的等待,而我們更希望的是提供給用戶一個上傳或下載的實時進度,這樣用戶體驗就大大提高了。
要實現上述的需求,這就要求我們發送了上傳或下載請求后能夠監控到實時的進度信息,在官方axios
中的請求配置對象config
就為我們提供了關於文件上傳下載進度監控的屬性,分別是:onDownloadProgress
和 onUploadProgress
,我們可以通過這兩個屬性來實現對下載進度和上傳進度的監控。
接下來,我們也要為我們實現的axios
添加這兩個屬性並且能夠實時監控上傳和下載的進度信息。其實,實現起來並不難,因為瀏覽器已經幫我們做好了,對於下載進度監控,XMLHttpRequest
對象提供了一個progress
事件,我們只需監聽該事件就能獲得當前數據下載的進度;而對於上傳進度的監控,XMLHttpRequest.ipload
對象提供了一個progress
事件,我們只需監聽該事件就能獲得當前數據上傳的進度;
OK,這就是實現思路,有了思路以后我們着手實現吧。
2. 向請求配置對象添加屬性
請求配置對象config
中添加 onDownloadProgress
和 onUploadProgress
這兩個屬性之前,我們需要先在src/types/index.ts
中的配置對象的接口類型定義AxiosRequestConfig
上添加該屬性的定義,如下:
export interface AxiosRequestConfig {
// 新增
onDownloadProgress?: (e: ProgressEvent) => void;
onUploadProgress?: (e: ProgressEvent) => void;
}
添加好以后,我們只需在發送請求之前判斷用戶是否配置了這兩個屬性,如果配置了就把該屬性掛載到XMLHttpRequest
對象上即可。
3. 把屬性添加到XMLHttpRequest上
我們只需在發送請求之前判斷用戶是否配置了這兩個屬性,如果配置了就把該屬性掛載到XMLHttpRequest
對象上即可,如下:
const {
// 新增
onDownloadProgress,
onUploadProgress
} = config;
if (onDownloadProgress) {
request.onprogress = onDownloadProgress;
}
if (onUploadProgress) {
request.upload.onprogress = onUploadProgress;
}
4. 潛在問題
這里有一個潛在的問題:由於我們之前給請求頭headers
設置了"Content-Type": "application/x-www-form-urlencoded"
,但是當我們通過 FormData
上傳文件的時候,這個Content-Type
字段就不能用了,就需要讓瀏覽器自動根據請求數據設置 Content-Type
,所以我們需要在添加請求頭之前加一個判斷,判斷請求發送的數據data
是不是 FormData
類型,是的話就要刪除掉之前配置的Content-Type
字段,讓瀏覽器自己去加。
首先,我們先在src/helpers/util.ts
中來創建一個工具函數isisFormData
,用來判斷請求數據data
是否為FormData
類型,如下:
export function isFormData(val: any): boolean {
return typeof val !== "undefined" && val instanceof FormData;
}
然后將判斷邏輯加入到添加請求頭之前,如下:
// src/core/xhr.ts
if (isFormData(data)) {
delete headers["Content-Type"];
}
OK,這樣我們就把文件上傳下載監控屬性就添加到我們的axios
上了,接下里我們就編寫demo
來測試下效果。
5. demo編寫
在 examples
目錄下創建 progressMonitor
目錄,在 progressMonitor
目錄下創建 index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>progressMonitor demo</title>
</head>
<body>
<h1>文件下載</h1>
<div>
<button id="download" class="btn btn-primary">Download</button>
</div>
<h1>文件上傳</h1>
<form role="form" class="form" onsubmit="return false;">
<input id="file" type="file" class="form-control" />
<button id="upload" type="button" class="btn btn-primary">Upload</button>
</form>
<script src="/__build__/progressMonitor.js"></script>
</body>
</html>
接着再創建 app.ts
作為入口文件:
import axios from "../../src/axios";
const instance = axios.create({
onDownloadProgress: function(ProgressEvent) {
const load = ProgressEvent.loaded;
const total = ProgressEvent.total;
const progress = (load / total) * 100;
console.log(progress);
},
onUploadProgress: function(ProgressEvent) {
const load = ProgressEvent.loaded;
const total = ProgressEvent.total;
const progress = (load / total) * 100;
console.log(progress);
}
});
const downloadBtn = document.getElementById("download");
downloadBtn!.onclick = function() {
instance.get("/api/downloadFile");
};
const uploadBtn = document.getElementById("upload");
uploadBtn!.onclick = function() {
const data = new FormData();
const file = document.getElementById("file") as HTMLInputElement;
if (file.files) {
data.append("file", file.files[0]);
instance.post("/api/uploadFile", data);
}
};
在本demo
中,我們分別創建了文件下載和上傳的兩個場景,然后在axios
請求配置對象中配置了 onDownloadProgress
和 onUploadProgress
這兩個屬性,並且在屬性內部打印了進度信息。
接着在 server/server.js
添加新的接口路由:
// 文件下載
router.get("/api/downloadFile", function(req, res) {
res.sendFile(__dirname + "/1.mp4");
});
此處沒有編寫文件上傳的路由接口,我們主要是想觀察是否能夠監控到上傳進度,至於能否上傳成功不是我們關心的。
最后在根目錄下的index.html
中加上啟動該demo
的入口:
<li><a href="examples/progressMonitor">progressMonitor</a></li>
OK,我們在命令行中執行:
# 同時開啟客戶端和服務端
npm run server | npm start
接着我們打開 chrome
瀏覽器,訪問 http://localhost:8000/ 即可訪問我們的 demo
了,我們點擊 progressMonitor
,就可以看到我們寫好的上傳下載場景了,分別點擊上傳和下載按鈕,在控制台就可以看到打印出來的實時進度。
OK,以上就是文件上傳下載進度監控的功能實現。
(完)