You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

拖拽文件上传中Ajax进度监听器异常问题求助

如何正确实现XMLHttpRequest上传进度监听?

我明白你遇到的问题——上传进度监听要么没反应要么只触发一次,这在使用XMLHttpRequest做文件上传时是很常见的坑。咱们来一步步解决它:

先分析你之前尝试的问题

  1. 第一种尝试的错误:

    request.upload = function(){console.log("me")}
    

    这完全不符合API规范:request.upload是一个XMLHttpRequestUpload对象,不是可赋值的函数。你需要给这个对象添加事件监听器,而不是覆盖它。

  2. 第二种尝试只触发一次的原因:
    大概率是你添加监听器的时机不对——必须在调用request.open()之前(或者至少在request.send()之前)绑定upload的进度事件,否则浏览器可能已经开始发送数据,早期的进度事件会被错过。如果文件很小,浏览器瞬间发送完成,也会看起来只触发一次,可以用大文件测试验证。


修正后的完整代码

下面是调整后的拖拽上传代码,已经正确实现了上传进度监听:

(function(){ 
  var dropzone = document.getElementById('dropzone'); 

  var uploadFile = function (files) { 
    var formData = new FormData(); 
    var request = new XMLHttpRequest(); 
    var totalSize = 0; 

    // 遍历文件,添加到FormData并计算总大小
    for(var i = 0; i < files.length; i++){ 
      formData.append('file[]', files[i]); 
      totalSize += files[i].size; 
    } 

    // 👉 关键:先绑定上传进度监听器,再执行open/send
    request.upload.addEventListener("progress", progressBar, false); 

    // 上传完成后的处理
    request.onload = function(){ 
      if (this.status >= 200 && this.status < 300) {
        console.log('上传成功!');
        // window.location.reload(); 
      } else {
        console.error('上传失败,状态码:', this.status);
      }
    }; 

    // 上传出错的处理
    request.onerror = function() {
      console.error('上传请求发生错误,请检查网络或后端服务');
    };

    // 打开请求并发送数据
    request.open('POST', 'dragNdrop.php?isNotSet=set'); 
    request.send(formData); 
  }; 

  // 进度条更新函数
  function progressBar(event){ 
    // 确保浏览器能获取到总大小,避免计算错误
    if (event.lengthComputable) {
      var percent = Math.round((event.loaded / event.total) * 100); 
      console.log(`${percent}% | 已上传:${event.loaded}字节 | 总大小:${event.total}字节`); 
      // 这里可以添加DOM操作来更新页面上的进度条,比如:
      // document.getElementById('progress-bar').style.width = percent + '%';
    }
  }

  dropzone.ondragover = function(){ 
    this.className = 'dropzone dragover'; 
    return false; 
  }; 

  dropzone.ondragleave = function(){ 
    this.className = 'dropzone'; 
    return false; 
  }; 

  dropzone.ondrop = function (event) { 
    event.preventDefault(); 
    this.className = 'dropzone'; 
    uploadFile(event.dataTransfer.files); 
    return false; 
  } 
}()); 

关键注意事项

  1. 监听器绑定顺序:必须先给request.upload添加事件监听器,再调用request.open()和request.send(),否则会错过早期的进度事件。
  2. 检查event.lengthComputable:有些情况下浏览器无法获取文件总大小(比如跨域或服务器返回的头信息问题),这时候event.total会是0,需要先判断再计算百分比,避免NaN错误。
  3. 大文件测试:如果测试用的文件太小,浏览器会瞬间完成上传,进度事件可能只触发一次,建议用几百MB的文件测试,就能看到多次进度更新。
  4. 后端兼容性:虽然前端进度是浏览器监控发送字节数,但如果后端启用了强制缓冲(比如PHP的ob_start()),理论上不影响上传进度监听,但如果是后端处理上传的进度(比如接收文件的进度),那需要额外的后端配置,但前端的upload进度和这个无关。

内容的提问来源于stack exchange,提问作者user9697902

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:59:58