告别理论,手把手带你打通前后端交互的任督二脉
写在前面
作为一名前端开发者,我们每天都和Ajax打交道。但你真的理解它的工作原理吗?今天,我将带你从零开始,用原生JavaScript + Node.js实现一个完整的待办事项应用,彻底搞懂前后端交互的每一个环节。
一、为什么需要Ajax?
传统的网页交互是这样的:用户点击链接 → 浏览器向服务器请求完整页面 → 服务器返回新页面 → 页面刷新。这种体验有多糟糕,相信大家都深有体会。
Ajax(Asynchronous JavaScript and XML)的出现彻底改变了这一局面。它让我们可以在不刷新页面的情况下,向服务器请求数据并更新部分页面内容。
核心原理图解
text
markdown
用户操作 → JavaScript发起请求 → 服务器处理
↓
页面无刷新更新 ← 回调函数处理响应 ← 返回数据
二、数据交换的桥梁:JSON
在网络传输中,我们需要一种通用格式来传递数据。JSON(JavaScript Object Notation)就是这个标准。
JSON.stringify() 详解
javascript
javascript
// 基本用法
const todo = { id: 1, title: '学习Ajax', completed: false };
const jsonStr = JSON.stringify(todo);
// 输出: '{"id":1,"title":"学习Ajax","completed":false}'
// 带格式化参数的用法
const prettyJson = JSON.stringify(todo, null, 2);
// 输出:
// {
// "id": 1,
// "title": "学习Ajax",
// "completed": false
// }
参数说明:
value:要转换的对象replacer:过滤函数,null表示不过滤space:缩进空格数,提升可读性(团队规范必备)
三、服务端搭建:Node.js + HTTP模块
CommonJS模块化系统
早期的JavaScript没有模块化概念,Node.js通过require + module.exports实现了CommonJS规范。
javascript
javascript
// 引入Node内置的http模块
const http = require('http');
// 待办数据
const todos = [
{ id: 1, title: '学习服务器端', completed: false },
{ id: 2, title: '学习ES6', completed: false },
{ id: 3, title: '掌握Ajax', completed: false }
];
// 创建HTTP服务器
const server = http.createServer((req, res) => {
// 根据请求路径返回不同内容
if (req.url === '/') {
res.end('hello world');
}
if (req.url === '/todos') {
// 解决跨域问题
res.setHeader('Access-Control-Allow-Origin', '*');
// 设置响应头:告诉浏览器返回的是JSON格式
res.setHeader('Content-Type', 'application/json;charset=utf-8');
// 将对象转为字符串并返回
res.end(JSON.stringify(todos));
}
});
// 监听3000端口
server.listen(3000, () => {
console.log('Server is running on 3000 port');
});
关键技术点
| 知识点 | 说明 |
|---|---|
req.url |
获取客户端请求的URL路径 |
res.setHeader() |
设置响应头,解决跨域和内容类型问题 |
res.end() |
返回响应,底层传输的是二进制数据 |
listen(port) |
监听指定端口 |
四、前端请求:从XHR到Fetch
XMLHttpRequest 原生实现
这是Ajax最原始的实现方式,虽然代码稍显繁琐,但理解它是掌握所有异步请求的基础。
html
xml
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>待办事项应用</title>
</head>
<body>
<ul id="todos"></ul>
<button id="btn">获取待办列表</button>
<script>
// 获取DOM元素
const btn = document.getElementById('btn');
const todosList = document.getElementById('todos');
// 事件监听
btn.addEventListener('click', function() {
// 1. 创建XHR对象
const xhr = new XMLHttpRequest();
// 2. 打开HTTP通道(异步请求)
xhr.open('GET', 'http://localhost:3000/todos', true);
// 3. 监听响应状态变化
xhr.onreadystatechange = function() {
console.log('当前readyState:', xhr.readyState);
// readyState === 4 表示请求完成
// status === 200 表示成功
if (xhr.readyState === 4 && xhr.status === 200) {
// 将JSON字符串解析为对象
const todos = JSON.parse(xhr.responseText);
// 动态渲染页面
todosList.innerHTML = todos
.map(todo => `<li>${todo.title}</li>`)
.join('');
}
};
// 4. 发送请求
xhr.send();
});
console.log('end'); // 验证异步特性
</script>
</body>
</html>
XHR的readyState状态码
| 状态值 | 含义 |
|---|---|
| 0 | 未初始化,尚未调用open() |
| 1 | 已打开,已调用open() |
| 2 | 已发送,已调用send() |
| 3 | 接收中,正在下载响应体 |
| 4 | 完成,响应已就绪 |
Fetch API(现代替代方案)
javascript
javascript
// 更简洁的Fetch写法
fetch('http://localhost:3000/todos')
.then(res => res.json()) // 解析JSON
.then(data => console.log(data)); // 处理数据
五、JavaScript异步编程进阶
JavaScript是单线程语言,异步任务需要放在事件循环(Event Loop)中执行。
三种异步处理方式对比
javascript
javascript
// 方式一:回调函数(XHR就是这种)
xhr.onreadystatechange = function() {
// 回调地狱的雏形
};
// 方式二:Promise + then()
fetch(url)
.then(res => res.json())
.then(data => handleData(data))
.catch(err => console.error(err));
// 方式三:async/await(最推荐)
async function getTodos() {
try {
const res = await fetch('http://localhost:3000/todos');
const data = await res.json();
console.log(data);
} catch (error) {
console.error('请求失败:', error);
}
}
为什么async/await最优?
- 语法同步化:代码看起来像同步执行,实际是异步
- 错误处理统一:使用try/catch捕获所有错误
- 避免嵌套地狱:不再有.then链式调用的冗长代码
六、运行你的第一个全栈应用
启动步骤
bash
bash
# 1. 启动Node服务器
node index.js
# 输出: Server is running on 3000 port
# 2. 用浏览器打开index.html
# 3. 点击按钮,查看效果
常见问题排查
| 问题 | 解决方案 |
|---|---|
| 跨域错误 | 服务端设置Access-Control-Allow-Origin: * |
| 中文乱码 | 响应头添加charset=utf-8 |
| 数据无法显示 | 确认JSON.parse()是否正确 |
写在最后
今天我们完成了一个完整的前后端交互应用,涉及的知识点包括:
- ✅ Ajax核心原理与XHR实现
- ✅ JSON数据序列化与解析
- ✅ Node.js HTTP模块搭建服务
- ✅ CommonJS模块化规范
- ✅ 异步编程的三种方式对比
这些知识构成了前端开发的基石,无论你使用React、Vue还是其他框架,底层原理都是相通的。
思考题: 如果我想添加"新增待办"的功能,前后端代码需要怎么修改?欢迎在评论区交流讨论!
如果觉得文章对你有帮助,欢迎点赞、收藏、关注三连支持一下~