axios進度條功能onDownloadProgress函式total引數為undefined問題

水冗水孚發表於2023-04-18

問題描述

  • 使用axios發請求,想要實現一個請求的結果進度
  • 比如當網路慢的情況,或者某個請求返回的資料量比較大的情況等
  • 最常見的就是下載一個大檔案,要檢視大檔案下載的進度
  • axios的onDownloadProgress函式已經幫我們封裝好了
  • 是基於原生的ProgressEvent套殼子的

比如我們下載一個流檔案,要呈現下載的進度,在這裡列印一下進度事件

axios({
    method: "get",
    responseType: "blob", // 流檔案為blob型別
    url: "http://ashuai.work:10000/getDoc",
    onDownloadProgress(ProgressEvent) {
        console.log('進度事件', ProgressEvent);
    }
}).then(({ data }) => {
    console.log('介面請求完成',data);
});

列印結果如下圖:

這裡為何拿不到total的值?

  • 是因為介面的響應頭,沒有返回Content-Length屬性
  • 所以ProgressEvent就拿不到這個值,所以就沒有total的值,就為undefined

請看響應頭

Content-Length 大家可以簡要理解成為一個介面返回的內容的總大小,單位位元組,我們知道了某個時刻loaded多少位元組,知道總位元組,就可以得出百分比了

解決方案

讓後端在響應頭上加上Content-Length即可

讓後端在響應頭上加上Content-Length即可

讓後端在響應頭上加上Content-Length即可

筆者這裡使用express演示一下程式碼:

route.get('/getDoc', (req, res) => {
  res.header('Access-Control-Allow-Origin', '*');
  
  // fs.statSync讀取檔案資訊,讀取當前目錄下的study.docx檔案
  let docxUrl = './doc/study.docx'
  const Myfilesize = fs.statSync(docxUrl).size // 拿到檔案位元組大小
  // 設定請求頭
  res.writeHead(200, {
    'Content-Type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    'content-length': Myfilesize // 加上即可
  })
  
  let readStream = fs.createReadStream(docxUrl) // 流檔案pipe管道返回
  readStream.pipe(res);
})

加上以後,響應頭就有Content-Length了,就能正常了

這樣的話,進度條效果也就有了

流檔案請求手動加上,普通的請求會自帶Content-Length的

程式碼附上

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.5/axios.js"></script>
    <title>請求介面進度</title>
</head>

<body>
    <button @click="goPreview">點選預覽word檔案</button>
    <br>
    <progress max="100" value="0"></progress> <span class="val">0</span>
    <script>
        let btn = document.querySelector('button')
        let prog = document.querySelector('progress')
        let v = document.querySelector('.val')
        btn.onclick = () => {
            axios({
                method: "get",
                responseType: "blob", // 流檔案為blob型別
                url: "http://ashuai.work:10000/getDoc",
                onDownloadProgress(ProgressEvent) {
                    let percent = Math.floor((ProgressEvent.loaded / ProgressEvent.total) * 100)
                    prog.setAttribute('value', percent)
                    v.innerHTML = percent + '%'
                    console.log('進度事件', ProgressEvent);
                }
            }).then(({ data }) => {
                console.log(data); // 後端返回的是流檔案
            });
        }
    </script>
</body>

</html>

相關文章