为何XMLHttpRequest.onreadystatechange可返回status而onload不行,二者如何选择
XMLHttpRequest 事件触发逻辑及使用建议
1. 为什么onload没有触发错误处理
onload 事件的触发前提是请求完整完成了HTTP收发流程,也就是客户端已经收到了服务端返回的完整响应(无论状态码是200还是404、500)。
你遇到的无反馈情况,是因为错误出现在HTTP响应生成之前:比如DNS解析失败、跨域请求被拦截、网络断开、目标地址完全不可达等,这类场景下客户端根本没收到任何有效HTTP响应,onload 不会触发,此时触发的是onerror事件,你没有监听该事件所以没有任何反馈。
补充:如果是404、500这类HTTP级别的错误,onload 是会正常触发的,你原本写的状态码判断逻辑可以正常工作。
2. 为什么onreadystatechange会触发两次错误
onreadystatechange 事件会在readyState(请求状态)每一次变化时都触发,正常请求的readyState会从0依次变到4:
- readyState = 2:已收到响应头
- readyState = 3:响应体加载中
- readyState = 4:响应全部加载完成
你没有在事件逻辑里加if (this.readyState === 4)的判断,所以当readyState变为2时,已经可以读取到status状态码,满足非200的条件就会报一次错;等readyState变为4时又会再执行一次逻辑,所以一共报错两次。
3. 二者如何选择,onload的正确使用方式
优先选onload,它是XMLHttpRequest 2.0标准新增的简化接口,默认对应readyState === 4的场景,不需要手动判断请求状态,逻辑更清晰,完全符合你的使用偏好。
你只需要补全缺失的异常事件监听即可覆盖所有错误场景,以下是修改后的可运行代码:
<!DOCTYPE html> <html> <head> <title>XMLHttpRequest</title> </head> <body> <script> var request = new XMLHttpRequest(); // 请求成功完成(收到完整HTTP响应,无论状态码) request.onload = function(){ // 不要只判断等于200,所有2xx状态码都属于请求成功 if(this.status >= 200 && this.status < 300){ document.getElementById("stat").innerHTML = this.status; document.getElementById("size").innerHTML = this.response.length; document.getElementById("data").innerHTML = JSON.parse(this.response); }else{ console.log("HTTP错误: " + this.status); } } // 网络层面错误(无响应返回) request.onerror = function(){ console.log("网络错误,请求失败,状态码:" + this.status); // 该场景下status固定为0 } // 可选:监听请求被主动取消的场景 request.onabort = function(){ console.log("请求已被取消"); } request.open('GET','https://hplussport.com/api/products'); request.send(); </script> <div> Response Data<br/> Status: <span id="stat">Loading...</span><br/> Size : <span id="size">Loading...</span> bytes<br/> Data : <span id="data">Loading...</span> </div> </body> </html>
内容的提问来源于stack exchange,提问作者MrMills
相关产品推荐
相关产品推荐

