在现代 Web 应用中,前端页面(客户端)动态地向后端服务器发送数据并接收响应,是实现一切复杂功能的基础。无论是用户注册、提交评论,还是保存应用状态,其核心都是将 JavaScript 对象包装成 JSON 格式,通过 HTTP 请求发送给服务器。
本篇权威指南将引导您从零开始,构建一个完整的“数据发送与回显”迷你项目。我们将:
- Fetch API:现代、基于 Promise 的标准方法。
- XMLHttpRequest (XHR):经典、但已显陈旧的传统方法。
通过这个实战项目,您将彻底掌握客户端与服务器进行 JSON 数据交换的完整流程和最佳实践。
核心代码速览 (TL;DR)
对于希望快速获取现代最佳实践的开发者,以下是使用 async/await 和 Fetch API 发送 POST 请求的标准模式。
方法:使用 Fetch API 发送 JSON 数据
/**
* 向指定 URL 发送 JSON 数据的异步函数。
* @param {string} url – 目标服务器端点。
* @param {object} data – 要发送的 JavaScript 对象。
* @returns {Promise<object>} – 解析后的服务器 JSON 响应。
*/
async function postJson(url = '', data = {}) {
try {
const response = await fetch(url, {
method: 'POST', // 指定请求方法为 POST
headers: {
// 关键头部,告知服务器我们发送的是 JSON 格式的数据
'Content-Type': 'application/json',
},
// 将 JavaScript 对象转换为 JSON 字符串
body: JSON.stringify(data),
});
// 检查响应是否成功
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
// 解析并返回 JSON 响应
return await response.json();
} catch (error) {
console.error('Error during fetch operation:', error);
throw error;
}
}
// 示例用法:
const userData = { name: 'Alice', email: 'alice@example.com' };
postJson('/api/users', userData)
.then(responseData => {
console.log('Success:', responseData);
})
.catch(error => {
console.error('Failure:', error);
});
前置知识
- HTML/CSS 基础:了解 <form>, <input>, <button>。
- JavaScript 基础:熟悉 DOM 操作、事件监听,并对 Promise 和 async/await 有基本了解。
- 环境准备:本地安装了 Node.js 和 npm (用于搭建我们的迷你服务器)。
目录
- 4.1 现代方法:使用 Fetch API (推荐)
- 4.2 传统方法:使用 XMLHttpRequest (了解历史)
- 5.1 关键概念:JSON.stringify 与 Content-Type
- 5.2 跨域问题 (CORS) 简介
1. 项目概览与目标
我们将构建一个包含两部分的迷你应用:
- 一个运行在 http://localhost:3000 的 Node.js 服务器,它有一个 API 端点,能够接收 JSON 数据并返回一个确认信息。
- 一个运行在本地文件系统的 HTML 页面,用户可以在页面上填写信息,点击按钮后,数据将被发送到上述服务器,并将服务器的响应显示在页面上。
2. 第一部分:搭建“接收方”——一个极简 Node.js/Express 服务器
没有服务器,前端的数据发送将“无的放矢”。让我们用几行代码快速搭建一个。
初始化项目:
在你的电脑上创建一个新文件夹(例如 json-sender-project),进入该文件夹,在终端中运行:
npm init -y
npm install express cors
这会初始化一个 Node.js 项目,并安装 express(一个流行的 web 框架)和 cors(用于处理跨域问题)。
创建服务器代码 (server.js):
在项目文件夹中创建一个名为 server.js 的文件,并填入以下内容:
const express = require('express');
const cors = require('cors');
const app = express();
const PORT = 3000;
// — 中间件 —
app.use(cors()); // 允许所有来源的跨域请求
app.use(express.json()); // 关键!解析 application/json 格式的请求体
// — 路由 —
app.post('/api/users', (req, res) => {
console.log('收到客户端发送的数据:');
console.log(req.body); // req.body 包含了客户端发送的 JSON 对象
// 简单验证
if (!req.body.name || !req.body.email) {
return res.status(400).json({
message: '错误:姓名和邮箱不能为空!'
});
}
// 发送成功响应
res.status(201).json({
message: `服务器已成功接收到用户 ${req.body.name} 的数据!`,
data: req.body
});
});
// — 启动服务器 —
app.listen(PORT, () => {
console.log(`服务器正在 http://localhost:${PORT} 上运行`);
});
启动服务器:
在终端中运行 node server.js。现在,你的数据接收方已经准备就绪!
3. 第二部分:构建“发送方”——前端 HTML 与 CSS
现在创建我们的前端页面。
HTML 代码 (index.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>JSON 数据发送器</title>
</head>
<body>
<div class="container">
<h1>向服务器发送 JSON 数据</h1>
<form id="user-form">
<div class="form-group">
<label for="name">姓名:</label>
<input type="text" id="name" required value="Alice">
</div>
<div class="form-group">
<label for="email">邮箱:</label>
<input type="email" id="email" required value="alice@example.com">
</div>
<button type="submit" class="btn">使用 Fetch 发送</button>
</form>
<div id="response-area" class="response-area">
<h2>服务器响应:</h2>
<pre id="response-pre"></pre>
</div>
</div>
</body>
</html>
CSS 代码 (style.css)
(此处省略基础的 CSS 代码,您可以根据自己的喜好设计表单和容器样式,确保界面清晰即可。)
4. 第三部分:实现数据发送的 JavaScript 逻辑
这是连接前端与后端的桥梁。
4.1 现代方法:使用 Fetch API (推荐)
Fetch 是现代浏览器内置的、基于 Promise 的 HTTP 请求接口,语法简洁且功能强大。
JavaScript 代码 (script.js)
const form = document.getElementById('user-form');
const responsePre = document.getElementById('response-pre');
const SERVER_URL = 'http://localhost:3000/api/users';
form.addEventListener('submit', async (event) => {
event.preventDefault(); // 阻止表单默认的提交行为
const name = document.getElementById('name').value;
const email = document.getElementById('email').value;
const userData = { name, email };
responsePre.textContent = '正在发送数据…';
try {
const response = await fetch(SERVER_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData),
});
const responseData = await response.json();
if (!response.ok) {
// 如果服务器返回错误状态 (如 400, 500)
throw new Error(responseData.message || `HTTP error! status: ${response.status}`);
}
responsePre.textContent = JSON.stringify(responseData, null, 2);
responsePre.style.color = '#2ecc71';
} catch (error) {
responsePre.textContent = `请求失败: ${error.message}`;
responsePre.style.color = '#e74c3c';
}
});
4.2 传统方法:使用 XMLHttpRequest (了解历史)
在 Fetch 出现之前,XMLHttpRequest (XHR) 是实现 AJAX 的唯一方式。它的语法更繁琐,基于事件回调。
// 使用 XHR 的等效实现
function sendWithXHR(userData) {
const xhr = new XMLHttpRequest();
xhr.open('POST', SERVER_URL, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
responsePre.textContent = JSON.stringify(JSON.parse(xhr.responseText), null, 2);
responsePre.style.color = '#2ecc71';
} else {
responsePre.textContent = `请求失败: ${xhr.statusText}`;
responsePre.style.color = '#e74c3c';
}
};
xhr.onerror = function() {
responsePre.textContent = '网络错误。';
responsePre.style.color = '#e74c3c';
};
xhr.send(JSON.stringify(userData));
}
// 在表单事件监听器中调用 sendWithXHR(userData);
通过对比可以明显看出,Fetch 和 async/await 的组合在代码结构、错误处理和可读性上都远胜于 XHR。
5. 深入探讨
5.1 关键概念:JSON.stringify 与 Content-Type
- JSON.stringify(): HTTP 请求体 (body) 只能是字符串或二进制数据。我们不能直接发送一个 JavaScript 对象。JSON.stringify() 的作用就是将 JavaScript 对象序列化为一个 JSON 格式的字符串,使其能够通过网络传输。
- Content-Type: application/json: 这个 HTTP 头部至关重要。它就像是给包裹贴上的“内容标签”,告诉服务器:“我发送给你的请求体是一段 JSON 格式的字符串,请用 JSON 解析器来处理它”。我们的 Express 服务器正是因为看到了这个头部,才启用了 express.json() 中间件来正确地解析请求体,并将其放入 req.body。
5.2 跨域问题 (CORS) 简介
出于安全原因,浏览器默认实行“同源策略”,禁止一个源(例如 file:/// 或 http://localhost:8080)的脚本向另一个源(例如 http://localhost:3000)发起 HTTP 请求。
为了允许这种跨源通信,服务器必须在响应中包含特定的 HTTP 头部。这就是 CORS (Cross-Origin Resource Sharing) 机制。在我们的服务器代码中,app.use(cors()) 这行代码就是让 express 自动为所有响应添加必要的 CORS 头部,从而“授权”我们的前端页面可以访问它的 API。
6. 总结
通过这个完整的实战项目,我们掌握了现代 Web 开发中数据通信的核心流程:
理解并熟练运用这一流程,是构建任何动态、数据驱动的 Web 应用的基石。




