AJAX – 向服务器发送请求

AJAX – 向服务器发送请求(中文讲解)

在 AJAX(Asynchronous JavaScript and XML)中,向服务器发送请求是实现动态数据交互的核心步骤。本教程将详细讲解如何使用 XMLHttpRequestfetch 向服务器发送 AJAX 请求,结合 Node.js、Express 和 MongoDB,展示 GET 和 POST 请求的实际应用,数据格式以 JSON 为主。内容包括步骤、实例、注意事项和最佳实践,力求简洁清晰。


1. AJAX 发送请求概述

  • 目的:通过 JavaScript 异步向服务器发送 HTTP 请求(如 GET、POST),获取或提交数据,并更新网页内容。
  • 常用工具
  • XMLHttpRequest:传统 AJAX 方法,适合精细控制。
  • fetch:现代 API,基于 Promise,语法简洁,推荐使用。
  • 数据格式:通常使用 JSON,服务器返回 JSON 字符串,客户端通过 JSON.parse()response.json() 解析。

2. 使用 XMLHttpRequest 发送请求

XMLHttpRequest 是经典的 AJAX 请求方式,适合需要兼容旧浏览器或精细控制的场景。

2.1 步骤

  1. 创建 XMLHttpRequest 对象
   const xhr = new XMLHttpRequest();
  1. 配置请求
    使用 open(method, url, async) 设置请求方法、URL 和异步标志:
  • method:如 "GET""POST"
  • url:服务器端点(如 "http://localhost:3000/users")。
  • asynctrue(异步,推荐)或 false(同步,已弃用)。
   xhr.open('GET', 'http://localhost:3000/users', true);
  1. 设置请求头(可选)
    对于 POST 请求,设置 Content-Type
   xhr.setRequestHeader('Content-Type', 'application/json');
  1. 监听响应
    使用 onreadystatechange 处理响应:
  • readyState=4:请求完成。
  • status=200:请求成功。
   xhr.onreadystatechange = function () {
     if (xhr.readyState === 4 && xhr.status === 200) {
       const data = JSON.parse(xhr.responseText);
       console.log(data);
     }
   };
  1. 发送请求
    使用 send() 发送,POST 请求可附带数据:
   xhr.send(); // GET 请求
   // 或
   xhr.send(JSON.stringify({ name: "张三" })); // POST 请求

2.2 示例:GET 请求

获取 MongoDB 用户数据:

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.status);
    }
  }
};
xhr.onerror = function () {
  console.error('网络错误');
};
xhr.send();

2.3 示例:POST 请求

提交新用户数据:

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) {
      console.log('添加成功:', JSON.parse(xhr.responseText));
    } else {
      console.error('请求失败:', xhr.status);
    }
  }
};
xhr.send(JSON.stringify({ name: "李四", age: 30 }));

3. 使用 Fetch 发送请求

fetch 是现代 AJAX 的首选,基于 Promise,语法更简洁,推荐用于新项目。

3.1 步骤

  1. 发送请求
    使用 fetch(url, options)options 可指定方法、头、请求体等:
   fetch('http://localhost:3000/users', {
     method: 'GET'
   });
  1. 处理响应
    使用 response.json() 解析 JSON 响应:
   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. POST 请求
    设置 methodbody
   fetch('http://localhost:3000/users', {
     method: 'POST',
     headers: { 'Content-Type': 'application/json' },
     body: JSON.stringify({ name: "李四", age: 30 })
   });

3.2 示例:GET 请求(使用 async/await)

async function loadUsers() {
  try {
    const response = await fetch('http://localhost:3000/users');
    if (!response.ok) throw new Error('网络错误');
    const users = await response.json();
    console.log(users);
  } catch (error) {
    console.error('错误:', error.message);
  }
}
loadUsers();

3.3 示例:POST 请求

async function addUser() {
  try {
    const response = await fetch('http://localhost:3000/users', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name: "王五", age: 28 })
    });
    if (!response.ok) throw new Error('网络错误');
    const result = await response.json();
    console.log('添加成功:', result);
  } catch (error) {
    console.error('错误:', error.message);
  }
}
addUser();

4. 完整实例:AJAX 请求与 MongoDB

以下是一个结合 Node.js、Express 和 MongoDB 的实例,展示如何通过 AJAX 发送 GET 和 POST 请求管理用户数据。

4.1 服务器端(server.js)

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'));

4.2 客户端(public/index.html)

<!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.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) {
            alert('添加成功');
            loadUsers();
          } else {
            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('网络错误');
        await response.json();
        alert('添加成功');
        loadUsers();
      } catch (error) {
        alert('添加失败:' + error.message);
      }
    }
  </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
  • 点击“加载用户”,显示用户列表。
  • 输入姓名和年龄,点击“添加用户(XMLHttpRequest)”或“添加用户(Fetch)”,添加用户并刷新列表。

5. JSON 在请求中的作用

  • 发送请求:POST 请求使用 JSON.stringify() 将数据转为 JSON 字符串(如 { name: "王五", age: 28 })。
  • 接收响应:服务器返回 JSON 字符串,XMLHttpRequest 使用 JSON.parse()fetch 使用 response.json() 解析。
  • MongoDB:查询结果是 JavaScript 对象,res.json() 自动转为 JSON 字符串。

6. 注意事项与最佳实践

  1. 跨域问题
  • 本例使用 CORS(Access-Control-Allow-Origin: *)允许跨域。
  • 生产环境应限制允许的域名。
  1. 错误处理
  • XMLHttpRequest:检查 readyStatestatus,使用 onerror
  • fetch:检查 response.ok,使用 try-catch
  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. 安全性
  • 验证用户输入,防止注入。
  • 使用 HTTPS 保护数据。
  1. 推荐 fetch
  • fetch 语法更简洁,基于 Promise,适合现代开发。
  • XMLHttpRequest 适用于旧项目或需特殊功能(如上传进度)。
  1. 调试
  • 使用浏览器开发者工具(Network 面板)检查请求。
  • 使用 JSON.stringify(data, null, 2) 格式化输出。

7. 总结

  • 发送 AJAX 请求
  • XMLHttpRequest:创建对象、配置请求、发送并处理响应。
  • fetch:更简洁,推荐使用,基于 Promise。
  • 实例功能:通过 GET 查询用户,POST 添加用户,结合 MongoDB 和 JSON。
  • JSON 角色:请求体和响应使用 JSON 格式,JSON.stringify()JSON.parse() 关键。
  • 最佳实践:处理跨域、错误、超时,优先使用 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 请求示例</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.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) {
            alert('添加成功');
            loadUsers();
          } else {
            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('网络错误');
        await response.json();
        alert('添加成功');
        loadUsers();
      } catch (error) {
        alert('添加失败:' + error.message);
      }
    }
  </script>
</body>
</html>

类似文章

发表回复

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