XmlHttpRequestUpload load事件触发时response为空的原因及获取响应的正确事件咨询
嗨,这个问题我之前踩过坑,一开始完全摸不着头脑,其实核心是搞混了XmlHttpRequestUpload的事件和XHR本身事件的分工,我给你拆解下:
首先得明确:xhr.upload上绑定的所有事件,都是只负责跟踪「上传阶段」的状态。比如progress是显示上传了多少数据,load则是告诉你「浏览器已经把所有要上传的内容都成功发送给服务器了」——但这时候,服务器可能刚收到请求还在处理,或者响应数据还在回传的路上,XHR对象还没把服务器返回的响应内容填充到response属性里。所以你在这个时机去调用JSON.parse(xhr.response),自然会因为空字符串报错。
那为什么浏览器控制台里能看到正确的响应呢?这是个容易迷惑人的点:控制台里显示的XHR对象是「引用类型」,当你在xhr.upload.load事件里暂停代码或者事后展开查看时,XHR已经完成了整个响应接收流程,所以你看到的是它最终的状态,但代码执行的那一刻,response确实是空的。
那正确的处理时机是什么?你应该监听XHR实例本身的load事件,而不是xhr.upload的load事件。XHR原生的load事件,是在整个请求-响应周期完全结束(上传完成+服务器响应完全接收并解析完毕)后才触发的,这时候xhr.status、xhr.response这些属性都是完全可靠的,不会出现解析错误。
给你调整下代码示例,一看就懂:
// 原来的错误写法:监听上传完成事件 // xhr.upload.addEventListener('load', () => { ... }); // 正确写法:监听整个请求完成事件 xhr.addEventListener('load', () => { if (xhr.status === 200) { resolve(UPLOAD_OK); } else { const message = JSON.parse(xhr.response)?.error; reject(new APIError(xhr.status, xhr.statusText, message)); } });
当然,如果需要跟踪上传的进度或者上传过程中的错误,用xhr.upload的事件是没问题的,但涉及到读取服务器响应的逻辑,一定要放到XHR本身的load事件里。
内容来源于stack exchange

