AJAX – 服务器 响应

AJAX – 服务器响应(中文讲解)

在 AJAX(Asynchronous JavaScript and XML)中,服务器响应是客户端通过异步 HTTP 请求(如 GET、POST)接收到的数据,用于动态更新网页内容。本教程将详细讲解如何处理 AJAX 服务器响应,结合 Node.js、Express 和 MongoDB,展示如何接收和解析 JSON 格式的响应,使用 XMLHttpRequestfetch 两种方式。内容包括步骤、实例、注意事项和最佳实践,力求简洁清晰。


1. AJAX 服务器响应概述

  • 定义:服务器响应是服务器对 AJAX 请求的返回数据,通常为 JSON 格式(现代主流),也可能是 XML、文本等。
  • 处理方式
  • XMLHttpRequest:通过 responseTextresponseXML 获取响应,结合 JSON.parse() 解析 JSON。
  • fetch:通过 response.json() 自动解析 JSON,或使用其他方法(如 text())处理不同格式。
  • 用途:接收服务器数据(如 MongoDB 查询结果)并更新页面内容,如显示用户列表、提交表单结果等。

2. 处理服务器响应的步骤

2.1 使用 XMLHttpRequest 处理响应

XMLHttpRequest 是传统 AJAX 方法,处理响应的关键在于监听 onreadystatechange 事件。

步骤

  1. 创建和配置请求
   const xhr = new XMLHttpRequest();
   xhr.open('GET', 'http://localhost:3000/users', true);
  1. 监听响应
  • 使用 onreadystatechange 检查 readyStatestatus
    • readyState=4:请求完成。
    • status=200:成功响应。
  • 获取响应数据:
    • xhr.responseText:返回字符串(通常为 JSON)。
    • xhr.responseXML:返回 XML 文档(较少使用)。
   xhr.onreadystatechange = function () {
     if (xhr.readyState === 4) {
       if (xhr.status === 200) {
         const data = JSON.parse(xhr.responseText); // 解析 JSON
         console.log(data);
       } else {
         console.error('请求失败,状态码:', xhr.status);
       }
     }
   };
  1. 发送请求
   xhr.send();

示例:处理 JSON 响应

const xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:3000/users', true);
xhr.onreadystatechange = function () {
  if (xhr.readyState === 4) {
    if (xhr.status === 200) {
      const users = JSON.parse(xhr.responseText);
      console.log('用户数据:', users);
    } else {
      console.error('错误:', xhr.statusText);
    }
  }
};
xhr.onerror = function () {
  console.error('网络错误');
};
xhr.send();

2.2 使用 Fetch 处理响应

fetch 是现代 AJAX 方法,基于 Promise,处理响应更简洁。

步骤

  1. 发送请求
   fetch('http://localhost:3000/users');
  1. 处理响应
  • 使用 response.json() 解析 JSON。
  • 检查 response.oktrue 表示状态码 200-299)。
   fetch('http://localhost:3000/users')
     .then(response => {
       if (!response.ok) throw new Error('网络错误');
       return response.json();
     })
     .then(data => console.log('用户数据:', data))
     .catch(error => console.error('错误:', error));
  1. 使用 async/await(推荐):
   async function getUsers() {
     try {
       const response = await fetch('http://localhost:3000/users');
       if (!response.ok) throw new Error('网络错误');
       const data = await response.json();
       console.log('用户数据:', data);
     } catch (error) {
       console.error('错误:', error.message);
     }
   }
   getUsers();

3. 完整实例:处理服务器响应

以下是一个结合 Node.js、Express 和 MongoDB 的实例,展示如何发送 AJAX 请求并处理 JSON 响应,包含 GET(查询用户)和 POST(添加用户)。

3.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 }); // 返回 JSON 响应
  } catch (error) {
    console.error('添加失败:', error);
    res.status(500).json({ error: '服务器错误' });
  } finally {
    await client.close();
  }
});

app.listen(3000, () => console.log('服务器运行在 http://localhost:3000'));
  • 说明
  • /users (GET):返回用户列表(JSON)。
  • /users (POST):接收 JSON 数据,插入新用户,返回成功消息。
  • CORS 允许跨域请求。

3.2 客户端(public/index.html)

使用 XMLHttpRequestfetch 处理服务器响应:

<!DOCTYPE html>
<html>
<head>
  <title>AJAX 响应处理</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()">添加用户(XMLHttpRequest)</button>
    <button onclick="addUserFetch()">添加用户(Fetch)</button>
  </div>
  <button onclick="loadUsers()">加载用户</button>
  <pre id="result">点击按钮加载用户数据...</pre>
  <script>
    // XMLHttpRequest 加载用户
    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) {
            const users = JSON.parse(xhr.responseText);
            document.getElementById('result').innerText = JSON.stringify(users, null, 2);
          } else {
            document.getElementById('result').innerText = `错误:${xhr.statusText} (${xhr.status})`;
          }
        }
      };
      xhr.onerror = function () {
        document.getElementById('result').innerText = '错误:网络错误';
      };
      xhr.send();
    }

    // XMLHttpRequest 添加用户
    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) {
            const response = JSON.parse(xhr.responseText);
            alert(response.message);
            loadUsers();
          } else {
            alert(`添加失败:${xhr.statusText}`);
          }
        }
      };
      xhr.onerror = function () {
        alert('网络错误');
      };
      xhr.send(JSON.stringify({ name, age, hobbies: ['未知'] }));
    }

    // Fetch 添加用户
    async function addUserFetch() {
      const name = document.getElementById('name').value;
      const age = parseInt(document.getElementById('age').value);
      if (!name || !age) {
        alert('请输入姓名和年龄');
        return;
      }
      try {
        const response = await fetch('http://localhost:3000/users', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ name, age, hobbies: ['未知'] })
        });
        if (!response.ok) throw new Error(`服务器错误:${response.status}`);
        const result = await response.json();
        alert(result.message);
        loadUsers();
      } catch (error) {
        alert(`添加失败:${error.message}`);
      }
    }
  </script>
</body>
</html>

3.3 MongoDB 数据准备

在 MongoDB 中插入测试数据:

use myDatabase
db.users.insertMany([
  { name: "张三", age: 25, hobbies: ["读书", "旅行"] },
  { name: "李四", age: 30, hobbies: ["编程", "运动"] }
])

3.4 运行和测试

  1. 启动服务器
   node server.js
  1. 访问客户端
  • 打开浏览器,访问 http://localhost:3000
  • 点击“加载用户”,显示用户列表(JSON 格式)。
  • 输入姓名和年龄,点击“添加用户(XMLHttpRequest)”或“添加用户(Fetch)”,添加用户并刷新列表。
  1. 响应示例
  • GET /users 响应:
    json [ { "_id": "someObjectId1", "name": "张三", "age": 25, "hobbies": ["读书", "旅行"] }, { "_id": "someObjectId2", "name": "李四", "age": 30, "hobbies": ["编程", "运动"] } ]
  • POST /users 响应:
    json { "message": "添加成功", "id": "someObjectId3" }

4. JSON 在响应处理中的作用

  • 服务器:使用 res.json() 返回 JSON 数据,内部调用 JSON.stringify()
  • 客户端
  • XMLHttpRequest:通过 xhr.responseText 获取 JSON 字符串,使用 JSON.parse() 解析。
  • fetch:通过 response.json() 自动解析 JSON。
  • MongoDB:查询结果是 JavaScript 对象,转换为 JSON 后传输。

5. 注意事项与最佳实践

  1. 响应状态检查
  • XMLHttpRequest:检查 xhr.status(200 表示成功,404、500 等表示错误)。
  • fetch:检查 response.ok(true 表示 200-299)。
  1. 错误处理
  • XMLHttpRequest:使用 onerror 捕获网络错误,检查 statusText
  • fetch:使用 try-catch 捕获错误。
   xhr.onerror = () => console.error('网络错误');
  1. JSON 解析安全
  • 使用 try-catch 防止无效 JSON 导致错误:
    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. 超时设置
  • XMLHttpRequest
    javascript xhr.timeout = 5000; xhr.ontimeout = () => console.error('请求超时');
  • fetch
    javascript const controller = new AbortController(); setTimeout(() => controller.abort(), 5000); fetch('http://localhost:3000/users', { signal: controller.signal });
  1. 推荐 fetch
  • fetch 语法简洁,基于 Promise,适合现代开发。
  • XMLHttpRequest 适用于需要进度监控(如文件上传)。
  1. 调试
  • 使用浏览器开发者工具(Network 面板)检查响应。
  • 使用 JSON.stringify(data, null, 2) 格式化输出。

6. 总结

  • 服务器响应:AJAX 通过 XMLHttpRequestresponseText)或 fetchresponse.json())接收 JSON 数据。
  • 实例功能:查询和添加 MongoDB 用户,处理 JSON 响应并更新页面。
  • JSON 角色:服务器返回 JSON,客户端解析后操作。
  • 最佳实践:检查状态码、捕获错误、设置超时,使用 fetch 优先。

如果你需要更复杂的功能(如处理 XML 响应、分页查询、文件上传),或想深入某部分,请告诉我,我会提供详细代码或指导!

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 响应处理</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()">添加用户(XMLHttpRequest)</button>
    <button onclick="addUserFetch()">添加用户(Fetch)</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) {
            const users = JSON.parse(xhr.responseText);
            document.getElementById('result').innerText = JSON.stringify(users, null, 2);
          } 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) {
            const response = JSON.parse(xhr.responseText);
            alert(response.message);
            loadUsers();
          } else {
            alert(`添加失败:${xhr.statusText}`);
          }
        }
      };
      xhr.onerror = function () {
        alert('网络错误');
      };
      xhr.send(JSON.stringify({ name, age, hobbies: ['未知'] }));
    }

    async function addUserFetch() {
      const name = document.getElementById('name').value;
      const age = parseInt(document.getElementById('age').value);
      if (!name || !age) {
        alert('请输入姓名和年龄');
        return;
      }
      try {
        const response = await fetch('http://localhost:3000/users', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ name, age, hobbies: ['未知'] })
        });
        if (!response.ok) throw new Error(`服务器错误:${response.status}`);
        const result = await response.json();
        alert(result.message);
        loadUsers();
      } catch (error) {
        alert(`添加失败:${error.message}`);
      }
    }
  </script>
</body>
</html>

类似文章

发表回复

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