在使用 XMLHttpRequest(XHR)对象进行异步网络请求时,xhr.send() 是一个核心方法,用于将请求数据发送到服务器,开发者在实际操作中可能会遇到各种与 xhr.send() 相关的报错问题,本文将深入分析这些报错的常见原因、排查方法以及解决方案,帮助开发者快速定位并解决问题。

常见报错类型及原因分析
1 "Uncaught TypeError: Failed to execute 'send' on 'XMLHttpRequest': Could not convert JavaScript object to string"
这种错误通常发生在尝试发送非字符串类型的数据时。xhr.send() 方法默认接受字符串或 Document 对象,如果直接传入 JavaScript 对象(如 {key: "value"}),浏览器会尝试将其转换为字符串,而对象无法直接转换,因此抛出错误。
2 "NetworkError: Failed to execute 'send' on 'XMLHttpRequest': Failed to load"
这类错误通常与网络连接或请求配置有关,可能是目标 URL 不存在、跨域策略限制、服务器返回 404/500 状态码,或是本地开发环境未正确配置代理,如果请求的协议或端口与当前页面不匹配(如 HTTP 请求 HTTPS 资源),也可能触发此错误。
3 "Uncaught DOMException: Failed to execute 'send' on 'XMLHttpRequest': The object's state must be OPENED"
此错误表明 XHR 对象的当前状态不符合发送请求的条件。xhr.send() 必须在 xhr.open() 方法调用后、请求未完成或未中止的状态下执行,如果开发者未按顺序调用方法,或重复调用 send() 而未正确处理请求状态,就会触发此异常。
排查与解决方案
1 数据类型转换问题
对于非字符串数据,需手动序列化,发送 JSON 数据时,应使用 JSON.stringify() 将对象转换为字符串:

const data = { name: "John", age: 30 };
xhr.send(JSON.stringify(data));
确保请求头 Content-Type 设置为 application/json,以告知服务器数据格式。
2 网络与跨域问题
- 检查 URL 有效性:确保请求的 URL 正确且服务器可访问。
- 处理跨域请求:如果涉及跨域,需在服务器端设置
Access-Control-Allow-Origin头部,对于非简单请求(如带自定义头的 POST 请求),还需启用预检请求(OPTIONS)。 - 本地开发代理:在开发环境中,可通过代理工具(如 Vue CLI 的
proxy配置)规避跨域限制。
3 状态管理错误
确保 xhr.open() 在 xhr.send() 之前调用,且请求未处于 unsent 或 done 状态,可以通过监听 xhr.readyState 变化来管理请求流程:
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
console.log("请求完成");
}
};
xhr.open("POST", "https://api.example.com/data");
xhr.send();
最佳实践与注意事项
- 错误监听:始终添加
onerror和onabort回调,捕获网络中断或请求中止的情况。 - 超时设置:通过
xhr.timeout设置请求超时时间,避免长时间等待:xhr.timeout = 5000; // 5秒超时 xhr.ontimeout = () => console.log("请求超时"); - 异步与同步:除非必要,否则避免使用同步请求(
xhr.open(method, url, false)),以免阻塞页面渲染。
相关问答 FAQs
Q1: 为什么 xhr.send() 发送 FormData 数据时仍报错?
A: 可能是未正确设置请求头 Content-Type,发送 FormData 时,浏览器会自动设置 Content-Type 为 multipart/form-data,并附加边界字符串,手动设置该头会导致错误,因此应移除相关代码:
// 错误示范
xhr.setRequestHeader("Content-Type", "multipart/form-data");
// 正确做法:不设置 Content-Type,让浏览器自动处理
Q2: 如何处理 xhr.send() 发送大文件时的内存问题?
A: 对于大文件,建议使用 Blob 或 FileReader 分块上传,或改用 fetch API 的 ReadableStream,可通过压缩文件、分片上传(如分 1MB 一块)降低内存压力。

const chunk = file.slice(0, 1024 * 1024); // 分割 1MB xhr.send(chunk);
通过以上方法,开发者可以系统性地解决 xhr.send() 报错问题,提升网络请求的稳定性和效率。