上节课我们认识了 AJAX 和 XHR 这个"送货小哥"。这节课正式学怎么用他:open 告诉他去哪、send 让他出发、onreadystatechange 监听货到了没有。最终判断成功的标准就一条:readyState === 4 且 status === 200。
XHR 就像那个送货小哥,他有几个固定的动作。你不需要全记住,先用熟最常用的几个:
| 语法 | 作用说明 |
|---|---|
| new XMLHttpRequest | 叫一个新的送货小哥。每次请求必须新建,不能复用。 |
| xhr.open(method, url, async) | 告诉小哥:用什么方式(GET/POST)、去哪拿货(url)、异步还是同步。async 默认 true(异步)。 |
| xhr.send(params) | 让小哥出发!GET 不传参,POST 把参数塞这里面。 |
| xhr.setRequestHeader(key, val) | 给小哥戴个"胸牌"(请求头)。POST 表单请求必须配置。 |
| xhr.onreadystatechange | 货到了打电话给你的"手机"。每次状态变化自动触发这个函数。 |
| xhr.readyState | 当前处于哪个阶段(0~4),像快递物流进度。 |
| xhr.status | HTTP 状态码。200 = 成功,404 = 地址找不到,500 = 后端报错。 |
| xhr.responseText | 后端寄回来的原始内容(一般是 JSON 字符串),需要 JSON.parse 才能用。 |
readyState 就像快递的物流状态:已下单、已发货、运输中、派送中、已签收。它有 0 到 4 五个值,只有 4 代表"已签收,货完整到手了"。
// readyState 5 个阶段,像快递物流追踪: // 0 UNSENT:已下单,还没叫快递来取 // → 对象刚创建,还没调 open,请求未初始化 // 1 OPENED:快递员已接单,正在路上取件 // → 已调用 open,浏览器和服务器之间的通道已建立 // 2 HEADERS_RECEIVED:快递公司已收到包裹单,开始分拣 // → 服务器接收完请求,返回了响应头(告诉你"收到了") // 3 LOADING:包裹正在运输途中,可能分好几段送到 // → 正在分段接收后端返回的数据(大数据会多次触发) // 4 DONE:包裹已签收,可以拆开了 // → 全部数据传输完毕,响应完整就绪,可以读取数据了
如果你只判断了 readyState === 4 而没判断 status === 200,就会发现有时候拿到的数据是报错页面——因为 4 只代表"数据传完了",不代表"传成功了"。服务器报错也会传完,所以必须同时判断 status === 200。
GET 请求的套路就四步,背下来以后闭着眼写:
// ===== 第一步:创建对象 =====
let xhr = new XMLHttpRequest(); // 叫一个新的送货小哥,去后台帮你拿货
// ===== 第二步:open 配置 =====
// GET 传参规则:参数拼在 URL 末尾,用 ? 连接,多个参数用 & 分隔
// 格式:地址?参数1=值1&参数2=值2
// 示例:list.json?page=1&size=10
let url = "list.json?page=1&size=10"; // 把参数拼在网址末尾,? 后面就是参数
xhr.open("get", url, true); // open(方式, 地址, 异步?)——告诉小哥去哪、用什么方式
// "get" = GET 请求
// true = 异步(项目里 99% 用异步)
// ===== 第三步:监听(货到了在这里处理) =====
xhr.onreadystatechange = function () { // 货到了打电话给你的手机,每次状态变化自动触发
// 两个条件同时满足才算成功:
// readyState === 4 → 数据传完了
// status === 200 → 服务器说"没问题,给你数据"
if (xhr.readyState === 4 && xhr.status === 200) { // 4=货拿完了 且 200=服务器说没问题
let json = xhr.responseText; // 拿到后端寄回来的原始内容(JSON 字符串)——是属性不加括号
let list = JSON.parse(json); // 翻译成 JS 对象,现在能用了
console.log("分页数据:", list); // 打印出来看看
}
};
// ===== 第四步:send 出发! =====
// GET 不传参,所以 send 里空着
xhr.send(); // 让小哥出发!括号空着因为 GET 不带参数
如果你把 onreadystatechange 写在 send 后面,就可能错过前几个状态——因为 某些情况下请求太快,状态变化发生得比你绑定监听还快。正确顺序:先绑定监听,再 send。
可能在什么地方用:
① 页面加载时拉取商品列表、用户信息;② 点击"下一页"按钮加载更多数据;③ 搜索框输入关键词后发请求查结果。
常见的问题:
① 忘记判断 status === 200,拿到 404 报错页也当数据用;② 顺序写反了——先 send 再绑定 onreadystatechange,监听永远不触发;③ GET 参数忘了拼 ?,直接写在 URL 后面变成了路径的一部分;④ 本地双击打开 HTML 发 GET 请求——浏览器拦截 file:// 协议的 AJAX。
解决思路:
① 牢记判断条件是 readyState === 4 && status === 200,两个缺一不可;② 代码顺序固定:new → open → 绑定 onreadystatechange → send,别乱;③ 本地开发必须用 VS Code 的 Live Server 打开页面,不能双击。
练习二:原生 AJAX GET 请求——新建 demo2.html:
① 在项目根目录创建 data.json,写入:
{"code":0,"data":[{"id":1,"name":"商品A","price":99},{"id":2,"name":"商品B","price":199}]}
② 用原生 XMLHttpRequest 发送 GET 请求获取 data.json,把商品列表渲染到页面的 ul 里;③ 请求时显示"数据加载中...",完成后隐藏;④ 如果状态码不是 200,页面显示"数据加载失败,请稍后重试"。
练习三:GET 请求传参——封装函数 getList(page, size),拼接 URL 并发送,把结果渲染到表格里。