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

JQuery+Ajax上传进度条提前达100%问题排查求助

问题分析与解决方案

嘿,这个问题我太熟悉了!你的进度条之所以“虚快”,核心原因是它只追踪了文件从浏览器传到你自己服务器的进度,完全没管服务器把文件传到AWS S3的过程。

当你选好文件点击上传后,浏览器很快把文件传给你的服务器(小文件几秒就完成,大文件也比传到S3快很多),这时候前端的progress事件就触发到100%了,但你的服务器还在后台慢悠悠地把文件往S3桶里传——这就是为什么进度条走完了,还得等一会儿文件才会出现在S3里。

两种解决思路

1. 前端直接上传到S3(最推荐)

跳过自己的服务器,让浏览器直接把文件传到S3,这样XHR的progress事件就能真实反映文件到S3的上传进度,进度条就完全准了。实现步骤如下:

第一步:后端生成S3预签名URL

你的后端(比如Django)需要生成一个带权限的预签名URL,前端用这个URL直接上传文件到S3:

import boto3
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def get_presigned_url(request):
    if request.method == 'GET':
        s3_client = boto3.client('s3')
        bucket_name = '你的S3桶名称'
        file_name = request.GET.get('filename')
        # 生成有效期1小时的PUT请求预签名URL
        presigned_url = s3_client.generate_presigned_url(
            'put_object',
            Params={'Bucket': bucket_name, 'Key': file_name},
            ExpiresIn=3600
        )
        return JsonResponse({'presigned_url': presigned_url})

第二步:前端修改上传逻辑

先请求后端拿到预签名URL,再直接用XHR上传到S3,同时监听真实进度:

$('#uploadButton').click(function(e) {
    e.preventDefault();
    var fileInput = $('#uploadFile')[0];
    if (!fileInput.files.length) return;

    var file = fileInput.files[0];
    // 先获取预签名URL
    $.get("{% url 'project:get_presigned_url' %}", {filename: file.name}, function(response) {
        $.ajax({
            xhr: function(){
                var xhr = new window.XMLHttpRequest();
                xhr.upload.addEventListener('progress', function(e){
                    if(e.lengthComputable) {
                        var percent = Math.round((e.loaded / e.total) * 100);
                        $('#progressBar')
                            .attr('aria-valuenow', percent)
                            .css('width', percent + "%")
                            .text(percent + "%");
                    }
                });
                return xhr;
            },
            url: response.presigned_url,
            type: 'PUT',
            data: file,
            processData: false,
            contentType: file.type, // 保持文件原类型
            success: function(){
                // 上传S3成功后,可通知后端做后续处理(比如记录文件路径)
                $.post("{% url 'project:upload_complete' %}", {filename: file.name}, function() {
                    location.reload();
                });
            },
            error: function(){
                alert('上传失败,请重试');
            }
        });
    });
});

注意事项

  • 要给你的S3桶配置CORS规则,允许前端域名的PUT请求:
    <CORSConfiguration>
      <CORSRule>
        <AllowedOrigin>你的前端域名(比如http://localhost:8000)</AllowedOrigin>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
      </CORSRule>
    </CORSConfiguration>
    

2. 保留服务器中转,实时同步S3上传进度

如果因为业务原因必须经过自己的服务器上传到S3,那得让服务器把上传到S3的进度实时反馈给前端:

  • 用WebSocket(比如Django Channels):服务器在上传S3的过程中,计算当前上传的百分比,通过WebSocket推送给前端,前端更新进度条。
  • 用轮询:前端每隔1-2秒请求一次后端的进度接口,后端返回当前文件上传到S3的进度,前端更新进度条。

这种方式相对复杂,因为需要处理服务器端的进度追踪和前后端的实时通信,所以更推荐第一种直接上传的方案。

总结

你的现有代码只监听了浏览器到服务器的上传,而服务器到S3的“最后一公里”完全没被追踪,这才导致进度条失真。换成前端直接上传S3的方案,就能完美解决这个问题啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:35:20