使用Typescript重構axios(二十五)——文件上傳下載進度監控


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就為我們提供了關於文件上傳下載進度監控的屬性,分別是:onDownloadProgressonUploadProgress,我們可以通過這兩個屬性來實現對下載進度和上傳進度的監控。

接下來,我們也要為我們實現的axios添加這兩個屬性並且能夠實時監控上傳和下載的進度信息。其實,實現起來並不難,因為瀏覽器已經幫我們做好了,對於下載進度監控,XMLHttpRequest對象提供了一個progress事件,我們只需監聽該事件就能獲得當前數據下載的進度;而對於上傳進度的監控,XMLHttpRequest.ipload對象提供了一個progress事件,我們只需監聽該事件就能獲得當前數據上傳的進度;

OK,這就是實現思路,有了思路以后我們着手實現吧。

2. 向請求配置對象添加屬性

請求配置對象config中添加 onDownloadProgressonUploadProgress這兩個屬性之前,我們需要先在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請求配置對象中配置了 onDownloadProgressonUploadProgress這兩個屬性,並且在屬性內部打印了進度信息。

接着在 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,以上就是文件上傳下載進度監控的功能實現。
(完)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM