AJAX – onreadystatechange 事件
AJAX – onreadystatechange 事件(中文讲解)
在 AJAX 中,onreadystatechange
是 XMLHttpRequest
对象的一个事件处理函数,用于监听 HTTP 请求的状态变化。它是处理服务器响应的核心机制,特别是在使用 XMLHttpRequest
进行异步请求时。以下是关于 onreadystatechange
事件的详细中文讲解,涵盖其定义、用法、结合 Node.js 和 MongoDB 的实例,以及与 JSON 的关系,力求简洁清晰。
1. 什么是 onreadystatechange 事件?
- 定义:
onreadystatechange
是XMLHttpRequest
对象的事件处理属性,当请求的状态(readyState
)发生变化时触发。开发者通过它处理服务器响应。 - 用途:监控 AJAX 请求的进度,获取服务器返回的数据(如 JSON),并更新页面。
- 触发时机:每次
readyState
属性变化时触发,通常在请求完成(readyState=4
)时处理响应。
2. readyState 和 status 属性
readyState
:表示请求的当前状态,值为 0 到 4:0
:未初始化(调用open()
之前)。1
:已打开(调用open()
后)。2
:已发送(调用send()
后,头信息已接收)。3
:接收中(正在接收响应体)。4
:完成(响应接收完毕)。status
:HTTP 状态码,如:200
:成功。404
:未找到。500
:服务器错误。
典型检查:
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(JSON.parse(xhr.responseText)); // 处理 JSON 响应
}
};
3. 使用 onreadystatechange 的步骤
- 创建 XMLHttpRequest 对象:
const xhr = new XMLHttpRequest();
- 配置请求:
使用open(method, url, async)
初始化:
xhr.open('GET', 'http://localhost:3000/users', true);
- 绑定 onreadystatechange:
定义处理函数,检查readyState
和status
:
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
const data = JSON.parse(xhr.responseText);
console.log(data);
} else {
console.error('错误:', xhr.statusText);
}
}
};
- 发送请求:
xhr.send();
4. 完整实例:使用 onreadystatechange 处理响应
以下是一个结合 Node.js、Express 和 MongoDB 的实例,展示如何使用 onreadystatechange
处理 AJAX 请求的 JSON 响应。
4.1 服务器端(server.js)
创建 Node.js 服务器,从 MongoDB 返回用户数据:
const express = require('express');
const { MongoClient } = require('mongodb');
const app = express();
const uri = 'mongodb://localhost:27017/myDatabase';
const client = new MongoClient(uri);
app.use(express.json());
app.use(express.static('public'));
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST');
next();
});
app.get('/users', async (req, res) => {
try {
await client.connect();
const db = client.db('myDatabase');
const collection = db.collection('users');
const users = await collection.find({}).toArray();
res.json(users); // 返回 JSON
} catch (error) {
console.error('查询失败:', error);
res.status(500).json({ error: '服务器错误' });
} finally {
await client.close();
}
});
app.post('/users', async (req, res) => {
try {
await client.connect();
const db = client.db('myDatabase');
const collection = db.collection('users');
const user = req.body;
const result = await collection.insertOne(user);
res.json({ message: '添加成功', id: result.insertedId });
} catch (error) {
console.error('添加失败:', error);
res.status(500).json({ error: '服务器错误' });
} finally {
await client.close();
}
});
app.listen(3000, () => console.log('服务器运行在 http://localhost:3000'));
4.2 客户端(public/index.html)
使用 onreadystatechange
处理 GET 和 POST 请求的响应:
<!DOCTYPE html>
<html>
<head>
<title>AJAX onreadystatechange 示例</title>
<style>
pre { font-size: 16px; background: #f4f4f4; padding: 10px; }
button, input { padding: 10px; margin: 5px; }
</style>
</head>
<body>
<h1>用户管理</h1>
<div>
<input id="name" placeholder="姓名">
<input id="age" type="number" placeholder="年龄">
<button onclick="addUser()">添加用户</button>
</div>
<button onclick="loadUsers()">加载用户</button>
<pre id="result">点击按钮加载用户数据...</pre>
<script>
function loadUsers() {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:3000/users', true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
try {
const users = JSON.parse(xhr.responseText);
document.getElementById('result').innerText = JSON.stringify(users, null, 2);
} catch (error) {
document.getElementById('result').innerText = '错误:JSON 解析失败';
}
} else {
document.getElementById('result').innerText = `错误:${xhr.statusText} (${xhr.status})`;
}
}
};
xhr.onerror = function () {
document.getElementById('result').innerText = '错误:网络错误';
};
xhr.send();
}
function addUser() {
const name = document.getElementById('name').value;
const age = parseInt(document.getElementById('age').value);
if (!name || !age) {
alert('请输入姓名和年龄');
return;
}
const xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:3000/users', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
try {
const response = JSON.parse(xhr.responseText);
alert(response.message);
loadUsers();
} catch (error) {
alert('错误:JSON 解析失败');
}
} else {
alert(`添加失败:${xhr.statusText}`);
}
}
};
xhr.onerror = function () {
alert('网络错误');
};
xhr.send(JSON.stringify({ name, age, hobbies: ['未知'] }));
}
</script>
</body>
</html>
4.3 MongoDB 数据准备
在 MongoDB 中插入测试数据:
use myDatabase
db.users.insertMany([
{ name: "张三", age: 25, hobbies: ["读书", "旅行"] },
{ name: "李四", age: 30, hobbies: ["编程", "运动"] }
])
4.4 运行和测试
- 启动服务器:
node server.js
- 访问客户端:
- 打开浏览器,访问
http://localhost:3000
。 - 点击“加载用户”,
onreadystatechange
捕获响应,显示用户列表。 - 输入姓名和年龄,点击“添加用户”,
onreadystatechange
处理 POST 响应并刷新列表。
- 响应示例:
- GET
/users
:json [ { "_id": "someObjectId1", "name": "张三", "age": 25, "hobbies": ["读书", "旅行"] }, { "_id": "someObjectId2", "name": "李四", "age": 30, "hobbies": ["编程", "运动"] } ]
- POST
/users
:json { "message": "添加成功", "id": "someObjectId3" }
5. JSON 在 onreadystatechange 中的作用
- 响应数据:服务器返回 JSON 字符串,存储在
xhr.responseText
。 - 解析:使用
JSON.parse(xhr.responseText)
将 JSON 转为 JavaScript 对象。 - 错误处理:用
try-catch
确保 JSON 解析安全:
try {
const data = JSON.parse(xhr.responseText);
} catch (error) {
console.error('JSON 解析错误:', error.message);
}
6. 注意事项与最佳实践
- 检查 readyState 和 status:
- 只在
readyState === 4
处理响应。 - 检查
status === 200
确保成功。
if (xhr.readyState === 4 && xhr.status === 200) {
// 处理响应
}
- 错误处理:
- 使用
xhr.onerror
捕获网络错误:javascript xhr.onerror = () => console.error('网络错误');
- 检查非 200 状态码:
javascript if (xhr.status !== 200) { console.error('错误:', xhr.statusText); }
- JSON 解析安全:
- 始终用
try-catch
包裹JSON.parse()
:javascript try { const data = JSON.parse(xhr.responseText); } catch (error) { console.error('JSON 解析错误:', error.message); }
- 跨域问题:
- 本例使用 CORS(
Access-Control-Allow-Origin: *
)。 - 生产环境限制域名:
javascript res.header('Access-Control-Allow-Origin', 'http://trusted-domain.com');
- 超时设置:
- 设置请求超时:
javascript xhr.timeout = 5000; xhr.ontimeout = () => console.error('请求超时');
- 现代替代:
- 推荐
fetch
API,语法简洁:javascript fetch('http://localhost:3000/users') .then(response => response.json()) .then(data => console.log(data));
XMLHttpRequest
适合需要进度监控(如文件上传)。
- 调试:
- 使用浏览器开发者工具(Network 面板)检查响应。
- 使用
JSON.stringify(data, null, 2)
格式化输出。
7. 与 Fetch 的对比
特性 | XMLHttpRequest (onreadystatechange) | Fetch |
---|---|---|
语法 | 较繁琐,需手动检查状态 | 简洁,基于 Promise |
响应处理 | responseText , JSON.parse() | response.json() |
错误处理 | onerror , status 检查 | try-catch , response.ok |
现代性 | 传统,适合旧浏览器 | 现代,推荐使用 |
进度监控 | 支持(如上传进度) | 有限支持 |
8. 总结
- onreadystatechange:
XMLHttpRequest
的事件,监控请求状态,处理服务器响应。 - 实例功能:使用
onreadystatechange
处理 GET 和 POST 请求的 JSON 响应,结合 MongoDB 管理用户。 - JSON 角色:服务器返回 JSON,客户端通过
JSON.parse()
解析。 - 最佳实践:检查状态、捕获错误、设置超时,考虑
fetch
替代。
如果你需要更复杂功能(如上传进度、复杂查询),或想转换到 fetch
,请告诉我,我会提供详细代码或指导!
const express = require('express');
const { MongoClient } = require('mongodb');
const app = express();
const uri = 'mongodb://localhost:27017/myDatabase';
const client = new MongoClient(uri);
app.use(express.json());
app.use(express.static('public'));
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST');
next();
});
app.get('/users', async (req, res) => {
try {
await client.connect();
const db = client.db('myDatabase');
const collection = db.collection('users');
const users = await collection.find({}).toArray();
res.json(users);
} catch (error) {
console.error('查询失败:', error);
res.status(500).json({ error: '服务器错误' });
} finally {
await client.close();
}
});
app.post('/users', async (req, res) => {
try {
await client.connect();
const db = client.db('myDatabase');
const collection = db.collection('users');
const user = req.body;
const result = await collection.insertOne(user);
res.json({ message: '添加成功', id: result.insertedId });
} catch (error) {
console.error('添加失败:', error);
res.status(500).json({ error: '服务器错误' });
} finally {
await client.close();
}
});
app.listen(3000, () => console.log('服务器运行在 http://localhost:3000'));
<!DOCTYPE html>
<html>
<head>
<title>AJAX onreadystatechange 示例</title>
<style>
pre { font-size: 16px; background: #f4f4f4; padding: 10px; }
button, input { padding: 10px; margin: 5px; }
</style>
</head>
<body>
<h1>用户管理</h1>
<div>
<input id="name" placeholder="姓名">
<input id="age" type="number" placeholder="年龄">
<button onclick="addUser()">添加用户</button>
</div>
<button onclick="loadUsers()">加载用户</button>
<pre id="result">点击按钮加载用户数据...</pre>
<script>
function loadUsers() {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:3000/users', true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
try {
const users = JSON.parse(xhr.responseText);
document.getElementById('result').innerText = JSON.stringify(users, null, 2);
} catch (error) {
document.getElementById('result').innerText = '错误:JSON 解析失败';
}
} else {
document.getElementById('result').innerText = `错误:${xhr.statusText} (${xhr.status})`;
}
}
};
xhr.onerror = function () {
document.getElementById('result').innerText = '错误:网络错误';
};
xhr.send();
}
function addUser() {
const name = document.getElementById('name').value;
const age = parseInt(document.getElementById('age').value);
if (!name || !age) {
alert('请输入姓名和年龄');
return;
}
const xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:3000/users', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
try {
const response = JSON.parse(xhr.responseText);
alert(response.message);
loadUsers();
} catch (error) {
alert('错误:JSON 解析失败');
}
} else {
alert(`添加失败:${xhr.statusText}`);
}
}
};
xhr.onerror = function () {
alert('网络错误');
};
xhr.send(JSON.stringify({ name, age, hobbies: ['未知'] }));
}
</script>
</body>
</html>