使用jQuery AJAX上传文件时进度条始终直接显示100%问题求助
问题根因
该现象是典型的发送缓冲区截断进度上报导致的,核心有两个触发点:
- 客户端浏览器的TCP发送缓冲区:默认大小通常在10M~64M不等,小于缓冲区大小的文件会被系统一次性塞到发送队列里,浏览器会判定数据已经全部“发送完成”,直接触发
progress事件的loaded = total,所以会立刻看到100%。而2GB的大文件远大于缓冲区大小,需要分批写入队列,就能正常上报每一批的进度。
快速点击上传时偶尔能看到进度,是因为多个上传请求同时占满了发送缓冲区,后续数据只能等缓冲区排空后再写入,就能触发分段的进度上报。 - 服务端反向代理的请求缓冲区:如果使用Nginx、Apache这类Web服务器做反向代理,默认会开启请求体缓冲,以Nginx的
client_body_buffer_size配置为例,如果该值被设置为大于25M,25M的上传文件会被代理服务一次性全部读入内存再转发给后端PHP,此时前端看到的是上传到代理层的进度,自然会瞬间到100%,之后几秒的等待是代理层转发数据、PHP写入磁盘的耗时,所以Done会延迟输出。
解决方案
方案一:调整服务端缓冲区配置(优先)
如果使用Nginx,修改nginx.conf配置,把client_body_buffer_size调低到1M以内:
http { client_body_buffer_size 1M; }
修改后重载Nginx配置即可,小文件上传时超过缓冲区的部分会被代理写入临时文件分段处理,前端就能拿到正常的进度上报。
如果使用Apache,调整SendBufferSize参数到1M即可。
方案二:前端分块上传(服务端配置无法修改时使用)
把所有文件统一切成固定大小的块(示例按1M/块设置),逐块上传,每上传完成一块更新一次总进度,彻底规避缓冲区的影响:
const CHUNK_SIZE = 1 * 1024 * 1024; // 单块大小1M,可自行调整 $('#upload_form').submit(function(event){ event.preventDefault(); const file = $('#file_upload')[0].files[0]; const totalChunks = Math.ceil(file.size / CHUNK_SIZE); let uploadedChunks = 0; // 递归上传分块 async function uploadChunk(start) { const end = Math.min(start + CHUNK_SIZE, file.size); const chunk = file.slice(start, end); const fd = new FormData(); fd.append('file_upload', chunk); fd.append('filename', file.name); fd.append('totalChunks', totalChunks); fd.append('chunkIndex', uploadedChunks); await $.ajax({ url: "https://example.com/upload_file.php", method: "POST", data: fd, contentType: false, processData: false, }); uploadedChunks++; const percent = (uploadedChunks / totalChunks) * 100; console.log(percent); // 每传完一块更新进度 if (end < file.size) { await uploadChunk(end); } else { console.log('Done'); console.log('Always'); } } uploadChunk(0); })
后端同步修改PHP代码,接收所有分块后合并为完整文件即可。
内容的提问来源于stack exchange,提问作者InvictusMKS
相关产品推荐
相关产品推荐

