AJAX请求上传下载进度监控实现方式

2025-04-09 03:50

本文主要是介绍AJAX请求上传下载进度监控实现方式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《AJAX请求上传下载进度监控实现方式》在日常Web开发中,AJAX(AsynchronousJavaScriptandXML)被广泛用于异步请求数据,而无需刷新整个页面,:本文主要介绍AJAX请...

1. 前言

在日常 Web 开发中,AJAX(Asynchronous JavaScript and XML)被广泛用于异步请求数据,而无需刷新整个页面。然而,当涉及到上传下载文件或执行长时间运行的任务时,为了提升用户体验通常我们需要显示执行的进度条,那么监控请求的进度就变得尤为重要。

这里博主给大家讲解 XMLHttpRequestFetch API 以及 Axios封装 在进度监控上不同的实现方式

AJAX请求上传下载进度监控实现方式

进度监控的核心场景 :
1. 大文件上传/下载
2. 实时数据传输(如视频流)
3. 长耗时API请求
4. 用户交互反馈优化

2. 基于XMLHttpRequest的进度监控

javascript 中,XMLHttpRequest 提供了 progress 事件,允许我们监听请求的进度。

2.1 基础版文件上传监控

<input type="file" id="fileInput">
<progress id="uploadProgress" value="0" max="100"></progress>
<script>
document.getElementById('fileInput').addEventListener('change', function(e) {
  const file = e.target.files[0];
  if (!file) return;
  const xhr = new XMLHttpRequest();
  const progressBar = document.getElementById('uploadProgress');
  xhr.upload.addEventListener('progress', (e) => {
    if (e.lengthComputable) {
      const percent = (e.loaded / e.total) * 100;
      progressBar.value = percent;
      console.log(`上传进度: ${percent.toFixed(1)}%`);
    }
  });
  xhr.addEventListener('load', () => {
    console.log('上传完成');
  });
  xhr.open('POST', '/upload', true);
  xhr.send(file);
});
</script>

2.2 增强版多事件监控

我们还可以集合 progress 进行多事件监控,如下代码:

function uploadwipythonthProgress(file) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    // 上传进度监控
    xhr.upload.addEventListener('progress', (e) => {
      handleProgress('upload', e);
    });
    // 下载进度监控(当服务器返回大数据时)
    xhr.addEventListener('progress', (e) => {
      handleProgress('download', e);
    });
    xhr.addEventListener('error', reject);
    xhr.addEventListener('abort', reject);
    xhr.addEventListener('load', () => {
      if (xhr.status >= 200 && xhr.status < 300) {
        resolve(xhr.response);
      } else {
        reject(xhr.statusText);
      }
    });
    xhr.open('POST', '/upload');
    xhr.setRequestHeader('Content-Type', 'application/octet-stream');
    xhr.send(file);
    function handleProgress(type, e) {
      if (e.lengthComputable) {
        const percent = (e.loaded / e.total) * 100;
        console.log(`${type} progress: ${percent.toFixed(1)}%`);
      }
    }
  });
}

3. 基于Fetch API 的进度监控

3.1 Fetch API + ReadableStream实现下载监控

Fetch API 本身没有直接提供进度事件,但我们可以利用 ReadableStream 对响应体进行分段读取,从而计算已加载的字节数。

当第一次请求链接 await fetch(url) 的时候通过获取 headersContent-Length 返回的请求资源总大小,再结合 response.body.getReader() 来读取 body 内容来实现!

具体参考代码如下,小伙伴可以根据自身需求进行调整:

async function downloadLargeFile(url) {
  const response = await fetch(url);
  const reader = response.body.getReader();
  const contentLength = +response.headers.get('Content-Length');
  let receivedLength = 0;
  const chunks = [];
  while(true) {
    const {done, value} = await reader.read();
    if (done) break;
    chunks.push(value);
    receivedLength += value.length;
    const percent = (receivedLength / contentLength) * 100;
    console.log(`下载进度: ${percent.toFixed(1)}%`);
  }
  const blob = new Blob(chunks);
  return blob;
}
// 使用示例
downloadLargeFile('/large-file.zipCRfoyUOKW')
  .then(blob => {
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'file.zip';
    a.click();
  });

3.2 Fetch API 上传进度监控(伪方案)

Fetch API 原生并不支持上传进度监控。不过可以采用将文件包装成一个自定义的 ReadableStream 来实现 “伪”上传进度监控
需要注意的是,由于各浏览器对 Request 流处理的支持程度不一,该方法可能并非在所有环境下都能稳定工作。博主建议非必要不要采用这种方式

<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Fetch API 上传进度监控</title>
</head>
<body>
  <input type="file" id="fileInput">
  <button onclick="uploadFile()">上传文件</button>
  <progress id="progressBar" value="0" max="100"></progress>
  <span id="progressText">0%</span>
  <script>
    function uploadFile() {
      const fileInput = document.getElementById('fileInput');
      const file = fileInput.files[0];
      if (!file) {
        alert('请选择文件');
        return;
      }
      const progressBar = document.getElementById('progressBar');
      const progressText = document.getElementById('progressText');
      const total = file.size;
      let uploaded = 0;
      // 构造一个自定义的 ReadableStream 来包装文件流
      const stream = new ReadableStream({
        start(controller) {
          const reader = file.stream().getReader();
          function push() {
            reader.read().then(({ done, value China编程}) => {
              if (done) {
                controller.close();
                return;
              }
              uploaded += value.byteLength;
              const percent = (uploaded / total) * 100;
              progressBar.value = percent;
              progressText.innerText = percent.toFixed(2) + '%';
              controller.enqueue(value);
              push();
            }).catch(error => {
              console.error('读取文件错误:', error);
              controller.error(error);
            });
          }
          push();
        }
      });
      // 使用 Fetch API 发送 POST 请求
      fetch('/upload', {
        method: 'POST',
        headers: {
          // 根据后端要求设置合适的 Content-Type
          // 注意:如果使用 FormData 上传文件,浏览器会自动设置 multipart/form-data
          'Content-Type': 'application/octet-stream'
        },
        body: stream
      })
      .then(response => response.json())
      .then(data => {
        console.log('上传成功:', data);
        alert('上传完成');
      })
      .catch(error => {
        console.error('上传失败:', error);
        alert('上传失败');
      });
    }
  </script>
</body>
</html>

注意事项

  • 上传进度:Fetch API 本身不提供上传进度事件,上述方法通过包装文件流来模拟上传进度,但并非所有浏览器都支持这种方式,稳定性可能不如 XMLHttpRequest
  • 内容类型:如果后端要求 multipart/form-data 格式,建议仍采用 XMLHttpRequest 或使用 FormData 对象,因为自定义流方式上传数据可能需要后端特殊处理

4. Axios封装进度监控方案

通过封装 Axios 请求,可以同时监听上传和下载的进度,提升用户体验,再次之前我们先来看看未封装前最原始的上传和下载是如何实现的~

4.1 Axios 上传进度监控

Axios 支持通过配置项 onUploadProgress 来监听上传进度。以下示例展示了如何使用 Axios 上传文件,并在页面上显示进度信息:

<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <title>Axios 上传进度监控</title>
</head>
<body>
  <h2>文件上传(Axios)</h2>
  <input type="file" id="fileInput">
  <button onclick="uploadFile()">上传文件</button>
  <br>
  <progress id="uploadProgress" value="0" max="100"></progress>
  <span id="uploadText">0%</span>
  <!-- 引入 Axios 库 -->
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    function uploadFile() {
      const fileInput = document.getElementById('fileInput');
      const file = fileInput.files[0];
      if (!file) {
        alert('请选择文件');
        return;
      }
      const formData = new FormData();
      formData.append('file', file);
      axios.post('/upload', formData, {
        headers: {
          'Content-Type': 'multipart/form-data'
        },
        onUploadProgress: function (progressEvent) {
          if (progressEvent.lengthComputable) {
            const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total);
            document.getElementById('uploadProgress').value = percent;
            document.getElementById('uploadText').innerText = percent + '%';
          }
        }
      })
      .then(response => {
        alert('上传成功');
        console.log(response.data);
      })
      .catch(error => {
        alert('上传失败');
        console.error(error);
      });
    }
  </script>
</body>
</html>

代码解释:
使用 FormData 对象包装上传的文件;
通过 Axios 的 onUploadProgress 事件监听上传过程,并实时更新进度条和百分比显示。

4.2 Axios 下载进度监控

同理,Axios 还支持 onDownloadProgress 事件来监控文件下载进度。下面的示例展示了如何通过 Axios 下载文件并实时显示下载进度:

<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <title>Axios 下载进度监控</title>
</head>
<body>
  <h2>文件下载(Axios)</h2>
  <button onclick="downloadFile()">下载文件</button>
  <br>
  <progress id="downloadProgress" value="0" max="100"></progress>
  <span id="downloadText">0%</span>
  <!-- 引入 Axios 库 -->
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    function downloadFile() {
      axios.get('/download', {
        responseType: 'blob',  // 指定响应数据类型为 Blob
        onDownloadProgress: function (progressEvent) {
          if (progressEvent.lengthComputable) {
            const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total);
            document.getElementById('downloadProgress').value = percent;
            document.getElementById('downloadText').innerText = percent + '%';
          }
        }
      })
      .then(response => {
        // 创建一个临时链接下载文件
        const url = window.URL.createObjectURL(new Blob([response.data]));
        const a = doc编程ument.createElement('a');
        a.href = url;
        a.download = 'downloaded_file';
        document.body.appendChild(a);
        a.click();
        a.remove();
        window.URL.revokeObjectURL(url);
      })
      .catch(error => {
        alert('下载失败');
        console.error(error);
      });
    }
  </script>
</body>
</html>

代码解释:
1、我们通过 axios.get 请求下载文件,并设置 responseType 为 blob;
2、通过 onDownloadProgress 事件监听下载进度,并更新进度条;
3、下载完成后利用 Blob 和临时链接触发浏览器下载文件。

4.3 封装 Axios 实例

为了在项目中更方便地使用进度监控功能,可以将 Axios 进行封装。例如,我们可以创建一个 Axios 实例,并在请求配置中统一处理上传和下载进度

import axios from 'axios';
// 请求配置
const axiosInstance = axios.create({
  onUploadProgress: progressEvent => {
    const percent = Math.round(
      (progressEvent.loaded * 100) / progressEvent.total
    );
    console.log(`上传进度: ${percent}%`);
  },
  onDownloadProgress: progressEvent => {
    const percent = Math.round(
      (progressEvent.loaded * 100) / progressEvent.total
    );
    console.log(`下载进度: ${percent}%`);
  }
});
// 封装上传方法
async function axiosUpload(file) {
  const formData = new FormData();
  formData.append('file', file);
  try {
    const response = await axiosInstance.post('/upload', formData, {
      headers: {'Content-Type': 'multipart/form-data'}
    });
    return response.data;
  } catch (error) {
    console.error('上传失败:', error);
    throw error;
  }
}

使用时,在页面中调用封装方法即可,这样通过封装后的 Axios 实例,我们可以在项目中更加方便地复用进度监控功能。

5. 特殊场景处理技巧

通常在一些特殊场景下,针对进度监控我们还需要一些处理技巧,这里博主分享两个分别是 分块上传监控带宽计算与预估

5. 1 分块上传监控

async function chunkedUpload(file, chunkSize = 1024 * 1024) {
  const chunks = Math.ceil(file.size / chunkSize);
  let uploadedChunks = 0;
  for (let i = 0; i < chunks; i++) {
    const start = i * chunkSize;
    const end = Math.min(start + chunkSize, file.size);
    const chunk = file.slice(start, end);
    await axios.post('/upload-chunk', chunk, {
      headers: {'Content-Range': `bytes ${start}-${end-1}/${file.size}`},
      onUploadProgress: e => {
        const chunkPercent = (e.loaded / e.total) * 100;
        const totalPercent = ((uploadedChunks + e.loaded) / file.size) * 100;
        console.log(`分块进度: ${chunkPercent.toFixed(1)}%`);
        console.log(`总进度: ${totalPercent.toFixed(1)}%`);
      }
    });
    uploadedChunks += chunk.size;
  }
}

5. 2 带宽计算与预估

let startTime;
let lastLoaded = 0;
xhr.upload.addEventListener('progress', e => {
  if (!startTime) startTime = Date.now();
  const currentTime = Date.now();
  const elapsed = (currentTime - startTime) / 1000; // 秒
  const speed = e.loaded / elapsed; // bytes/s
  const remaining = (e.total - e.loaded) / speed; // 剩余时间
  console.log(`传输速度: ${formatBytes(speed)}/s`);
  console.log(`预计剩余时间: ${remai编程ning.toFixed(1)}秒`);
});
function formatBytes(bytes) {
  const units = ['B', 'KB', 'MB', 'GB'];
  let unitIndex = 0;
  while (bytes >= 1024 && unitIndex < units.length - 1) {
    bytes /= 1024;
    unitIndex++;
  }
  return `${bytes.toFixed(1)} ${units[unitIndex]}`;
}

6. 结语

本篇文章介绍了如何在前端请求中监控上传和下载进度,并提供了完整的前端和后端代码示例。通过合理运用这些技术,开发者可以构建出具有专业级进度反馈的Web应用,显著提升用户在处理大文件传输时的体验。

希望能帮助小伙伴们在项目中更好地处理大文件传输,提高用户体验!

到此这篇关于AJAX请求上传下载进度监控指南的文章就介绍到这了,更多相关AJAX上传下载内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程China编程(www.chinasem.cn)!

这篇关于AJAX请求上传下载进度监控实现方式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1154139

相关文章

SpringBoot实现微信小程序支付功能

《SpringBoot实现微信小程序支付功能》小程序支付功能已成为众多应用的核心需求之一,本文主要介绍了SpringBoot实现微信小程序支付功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作... 目录一、引言二、准备工作(一)微信支付商户平台配置(二)Spring Boot项目搭建(三)配置文件

鸿蒙中Axios数据请求的封装和配置方法

《鸿蒙中Axios数据请求的封装和配置方法》:本文主要介绍鸿蒙中Axios数据请求的封装和配置方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1.配置权限 应用级权限和系统级权限2.配置网络请求的代码3.下载在Entry中 下载AxIOS4.封装Htt

Spring中配置ContextLoaderListener方式

《Spring中配置ContextLoaderListener方式》:本文主要介绍Spring中配置ContextLoaderListener方式,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录Spring中配置ContextLoaderLishttp://www.chinasem.cntene

基于Python实现高效PPT转图片工具

《基于Python实现高效PPT转图片工具》在日常工作中,PPT是我们常用的演示工具,但有时候我们需要将PPT的内容提取为图片格式以便于展示或保存,所以本文将用Python实现PPT转PNG工具,希望... 目录1. 概述2. 功能使用2.1 安装依赖2.2 使用步骤2.3 代码实现2.4 GUI界面3.效

MySQL更新某个字段拼接固定字符串的实现

《MySQL更新某个字段拼接固定字符串的实现》在MySQL中,我们经常需要对数据库中的某个字段进行更新操作,本文就来介绍一下MySQL更新某个字段拼接固定字符串的实现,感兴趣的可以了解一下... 目录1. 查看字段当前值2. 更新字段拼接固定字符串3. 验证更新结果mysql更新某个字段拼接固定字符串 -

java实现延迟/超时/定时问题

《java实现延迟/超时/定时问题》:本文主要介绍java实现延迟/超时/定时问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java实现延迟/超时/定时java 每间隔5秒执行一次,一共执行5次然后结束scheduleAtFixedRate 和 schedu

Java Optional避免空指针异常的实现

《JavaOptional避免空指针异常的实现》空指针异常一直是困扰开发者的常见问题之一,本文主要介绍了JavaOptional避免空指针异常的实现,帮助开发者编写更健壮、可读性更高的代码,减少因... 目录一、Optional 概述二、Optional 的创建三、Optional 的常用方法四、Optio

在Android平台上实现消息推送功能

《在Android平台上实现消息推送功能》随着移动互联网应用的飞速发展,消息推送已成为移动应用中不可或缺的功能,在Android平台上,实现消息推送涉及到服务端的消息发送、客户端的消息接收、通知渠道(... 目录一、项目概述二、相关知识介绍2.1 消息推送的基本原理2.2 Firebase Cloud Me

Spring Boot项目中结合MyBatis实现MySQL的自动主从切换功能

《SpringBoot项目中结合MyBatis实现MySQL的自动主从切换功能》:本文主要介绍SpringBoot项目中结合MyBatis实现MySQL的自动主从切换功能,本文分步骤给大家介绍的... 目录原理解析1. mysql主从复制(Master-Slave Replication)2. 读写分离3.

Redis实现延迟任务的三种方法详解

《Redis实现延迟任务的三种方法详解》延迟任务(DelayedTask)是指在未来的某个时间点,执行相应的任务,本文为大家整理了三种常见的实现方法,感兴趣的小伙伴可以参考一下... 目录1.前言2.Redis如何实现延迟任务3.代码实现3.1. 过期键通知事件实现3.2. 使用ZSet实现延迟任务3.3