AJAX – onreadystatechange 事件

AJAX – onreadystatechange 事件(中文讲解)

在 AJAX 中,onreadystatechangeXMLHttpRequest 对象的一个事件处理函数,用于监听 HTTP 请求的状态变化。它是处理服务器响应的核心机制,特别是在使用 XMLHttpRequest 进行异步请求时。以下是关于 onreadystatechange 事件的详细中文讲解,涵盖其定义、用法、结合 Node.js 和 MongoDB 的实例,以及与 JSON 的关系,力求简洁清晰。


1. 什么是 onreadystatechange 事件?

  • 定义onreadystatechangeXMLHttpRequest 对象的事件处理属性,当请求的状态(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 的步骤

  1. 创建 XMLHttpRequest 对象
   const xhr = new XMLHttpRequest();
  1. 配置请求
    使用 open(method, url, async) 初始化:
   xhr.open('GET', 'http://localhost:3000/users', true);
  1. 绑定 onreadystatechange
    定义处理函数,检查 readyStatestatus
   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);
       }
     }
   };
  1. 发送请求
   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 运行和测试

  1. 启动服务器
   node server.js
  1. 访问客户端
  • 打开浏览器,访问 http://localhost:3000
  • 点击“加载用户”,onreadystatechange 捕获响应,显示用户列表。
  • 输入姓名和年龄,点击“添加用户”,onreadystatechange 处理 POST 响应并刷新列表。
  1. 响应示例
  • 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. 注意事项与最佳实践

  1. 检查 readyState 和 status
  • 只在 readyState === 4 处理响应。
  • 检查 status === 200 确保成功。
   if (xhr.readyState === 4 && xhr.status === 200) {
     // 处理响应
   }
  1. 错误处理
  • 使用 xhr.onerror 捕获网络错误:
    javascript xhr.onerror = () => console.error('网络错误');
  • 检查非 200 状态码:
    javascript if (xhr.status !== 200) { console.error('错误:', xhr.statusText); }
  1. JSON 解析安全
  • 始终用 try-catch 包裹 JSON.parse()
    javascript try { const data = JSON.parse(xhr.responseText); } catch (error) { console.error('JSON 解析错误:', error.message); }
  1. 跨域问题
  • 本例使用 CORS(Access-Control-Allow-Origin: *)。
  • 生产环境限制域名:
    javascript res.header('Access-Control-Allow-Origin', 'http://trusted-domain.com');
  1. 超时设置
  • 设置请求超时:
    javascript xhr.timeout = 5000; xhr.ontimeout = () => console.error('请求超时');
  1. 现代替代
  • 推荐 fetch API,语法简洁:
    javascript fetch('http://localhost:3000/users') .then(response => response.json()) .then(data => console.log(data));
  • XMLHttpRequest 适合需要进度监控(如文件上传)。
  1. 调试
  • 使用浏览器开发者工具(Network 面板)检查响应。
  • 使用 JSON.stringify(data, null, 2) 格式化输出。

7. 与 Fetch 的对比

特性XMLHttpRequest (onreadystatechange)Fetch
语法较繁琐,需手动检查状态简洁,基于 Promise
响应处理responseText, JSON.parse()response.json()
错误处理onerror, status 检查try-catch, response.ok
现代性传统,适合旧浏览器现代,推荐使用
进度监控支持(如上传进度)有限支持

8. 总结

  • onreadystatechangeXMLHttpRequest 的事件,监控请求状态,处理服务器响应。
  • 实例功能:使用 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>

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注