JavaScript发送HTTP请求主要有fetch()和XMLHttpRequest两条路径:fetch简洁基于Promise但默认不发Cookie,需credentials:'include';XHR兼容性好支持上传进度监听,但写法冗长需手动管理状态。

JavaScript 发送 HTTP 请求,核心就两条路:用 fetch() 或用 XMLHttpRequest(简称 XHR)。现代项目基本只用 fetch(),但理解 XHR 仍有价值——比如维护老代码、或需要精细控制请求生命周期(如手动中止、监听上传进度)。
fetch() 是当前标准,但默认不带 cookie
fetch() 简洁、基于 Promise,但有个关键细节常被忽略:默认不会发送 Cookie,也不会接收 Set-Cookie 响应头。这在登录态保持场景下直接导致 401 或反复跳转。
- 要携带 Cookie,必须显式传
{ credentials: 'include' } - 如果后端是跨域且用了
withCredentials,响应头必须包含Access-Control-Allow-Origin(不能是*),且通常还需Access-Control-Allow-Credentials: true - 没有内置超时机制,需靠
AbortController手动控制
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);
fetch('/api/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: 123 }),
credentials: 'include',
signal: controller.signal
})
.catch(err => {
if (err.name === 'AbortError') console.log('请求超时');
});
XMLHttpRequest 还没被淘汰,尤其需要上传进度或兼容 IE
虽然 XMLHttpRequest 写法冗长,但它支持监听 upload.onprogress、可同步阻塞(不推荐)、能 abort 中途请求,而且 IE10+ 全支持——fetch() 在 IE 中完全不可用。
- 必须手动调用
xhr.open()和xhr.send() - 状态判断靠
xhr.readyState和xhr.status,不是 Promise 链式调用 - 设置 Cookie 行为由
withCredentials控制,逻辑和fetch()的credentials一致
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/status');
xhr.withCredentials = true;
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(JSON.parse(xhr.responseText));
}
}
};
xhr.send();
别碰封装过度的“万能请求函数”
很多团队自己写 request() 封装,结果把 fetch() 的错误处理、重试、缓存、鉴权全塞进去,最后变成黑盒。问题来了:
立即学习“Java免费学习笔记(深入)”;
- 网络失败(如 DNS 解析失败、连接被拒)不会进
catch,而是直接 reject,但某些封装会吞掉这个 reject - HTTP 状态码如 404、500 默认不会 reject,得手动检查
response.ok,而封装层可能忘了这步 - 加了自动 JSON 解析,但遇到空响应体或非 JSON 内容就报错,调试时根本看不出原始响应
建议:初期就用原生 fetch() + try/catch + 显式 response.json(),等真正出现重复逻辑(比如统一鉴权 header)再抽离,而不是一上来就套壳。
真正容易出问题的,从来不是“用哪个 API”,而是对状态码、Cookie 传递、CORS 配置、错误边界这些细节的理解偏差。写完请求,务必用浏览器 Network 面板看实际发出的请求头、响应头、状态码,而不是只信控制台 log。











