XHR onreadystatechange内的for循环无法执行问题排查
Google Drive可恢复上传分块循环不执行的问题修复
核心问题及修复步骤
- 循环被提前终止:你在for循环的第一次迭代里就执行了
return res.status(200).json(...),这会直接跳出整个onreadystatechange回调函数,循环根本没机会继续执行。要把这个响应返回逻辑移到所有分块上传完成之后,要是需要实时返回进度,得用SSE这类方式,不能直接返回响应终止流程。 - 分块范围取值错误:循环里写
fileChunks.start和fileChunks.end是错的,fileChunks是数组,每个分块的起止应该对应fileChunks[i].start和fileChunks[i].end,不然拿不到当前循环的分块数据范围。 - 异步请求未按顺序处理:Google Drive的可恢复上传要求分块按顺序上传,不能并行发起请求。你现在的写法是循环里直接批量发起axios请求,会导致乱序,应该用
async/await等待每个分块上传完成后再处理下一个。 - 分块数据未正确传入:代码里的
buffer变量没有定义,应该传入当前分块的buffer,比如fileChunks[i].data,再转成流。
修正后的代码示例
xhr.onreadystatechange = async function () { if (this.readyState == this.HEADERS_RECEIVED) { // 解析响应头获取可恢复上传URI var headers = xhr.getAllResponseHeaders(); var arr = headers.trim().split(/[\r\n]+/); var headerMap = {}; arr.forEach(function (line) { var parts = line.split(": "); var header = parts.shift(); var value = parts.join(": "); headerMap[header] = value; }); const resumableURI = headerMap.location; console.log('resumable uri : ' + resumableURI); const fileChunks = divideFileInChunks(req.files.muploadedFile.data); const totalChunks = fileChunks.length; try { for (let i = 0; i < totalChunks; i++) { console.log(`正在上传第 ${i+1} 块,共 ${totalChunks} 块`); // 获取当前分块的信息 const chunk = fileChunks[i]; // 发起分块上传请求,用await等待完成 const resp = await axios.put(resumableURI, bufferToStream(chunk.data), { headers: { Authorization: `Bearer ${accessToken}`, "Content-Length": chunk.end - chunk.start + 1, // 当前分块的实际大小 "Content-Range": `bytes ${chunk.start}-${chunk.end}/${req.files.muploadedFile.size}` } }); console.log(`第 ${i+1} 块上传完成`, resp.data); } // 所有分块上传完成后再返回响应 return res.status(200).json({message: `所有 ${totalChunks} 块已上传完成`}); } catch (f) { console.error('上传失败', f); res.status(500).send(f.message); } } }; xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); xhr.setRequestHeader("Authorization", `Bearer ${accessToken}`); xhr.send( JSON.stringify({ name: req.files.muploadedFile.name, mimeType: req.files.muploadedFile.mimetype, }) );
额外注意事项
- 确保
divideFileInChunks函数返回的每个分块对象包含start(起始字节)、end(结束字节)、data(分块的buffer数据)三个核心属性。 - 如果需要实时给客户端推送上传进度,不能用一次性HTTP响应,应该使用服务器发送事件(SSE)或者WebSocket来逐步更新进度。
- 要处理分块上传失败的情况,比如某个分块上传失败,需要根据Google Drive API的响应重新发起该分块的上传,不要直接终止整个上传流程。
内容的提问来源于stack exchange,提问作者karthi keyan
相关产品推荐
相关产品推荐

