用 http 模块搭建 Web 服务器
🎯 引言
学完这篇文章,你能用 Node.js 内置的 http 模块启动一个 Web 服务器,根据访问地址返回不同内容,还能写出一个返回 JSON 数据的接口,迈出后端开发的关键一步。
🧱 先懂客户端与服务器
Web 的世界里有两种角色:客户端(比如浏览器)负责发请求,服务器负责接收请求并返回响应。
就像去餐厅点餐:你告诉服务员要吃什么,这是“请求”;厨房做好后端上来,这是“响应”。浏览器访问一个网址,背后就是这一套流程。Node.js 可以让我们的电脑扮演服务器的角色。
🛠 第一个服务器
创建 server.js,写入下面的代码:
import http from 'node:http';
// 创建服务器:每次有请求进来,这个回调函数就会执行
const server = http.createServer((req, res) => {
res.end('Hello Node.js Server');
});
// 监听 3000 端口,启动服务
server.listen(3000, () => {
console.log('服务器已启动:http://localhost:3000');
});
逐行理解:
createServer创建一个服务器实例,回调里的req是请求对象(客户端发来的信息),res是响应对象(我们回给客户端的内容)。res.end()结束响应并把内容发给客户端,每个请求都必须调用它,否则浏览器会一直转圈等待。listen(3000)让服务器监听 3000 端口,端口可以理解为这台电脑上的“服务窗口编号”。
运行 node server.js,浏览器打开 http://localhost:3000,就能看到返回的文字了。
🪤 中文乱码问题
把上面的返回内容改成中文试试:res.end('你好,世界')。浏览器很可能显示一堆乱码。
原因是浏览器不知道我们发的是什么编码。用 setHeader 明确告诉它:
const server = http.createServer((req, res) => {
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.end('你好,世界');
});
charset=utf-8 是初学者的高频踩坑点。记住:Content-Type 告诉浏览器“内容的类型和编码”,设置要在 res.end() 之前。🛠 简单路由
真实的服务器要根据访问地址返回不同内容,这就是路由。用 req.url 和 req.method 判断即可:
import http from 'node:http';
const server = http.createServer((req, res) => {
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
if (req.url === '/' && req.method === 'GET') {
res.end('欢迎来到首页');
} else if (req.url === '/about' && req.method === 'GET') {
res.end('这是关于页面');
} else {
// 没匹配到的地址,返回 404
res.statusCode = 404;
res.end('页面不存在');
}
});
server.listen(3000);
现在访问 / 和 /about 会看到不同内容,访问其他地址会收到 404。这就是路由的朴素实现:Express 等框架本质上就是把这套判断做得更优雅,后面的课程会专门学习。
🛠 返回 JSON 接口
前后端分离项目里,服务器经常返回 JSON 数据。把 Content-Type 换成 application/json,内容用 JSON.stringify 转换:
import http from 'node:http';
const server = http.createServer((req, res) => {
if (req.url === '/api/user') {
const user = { name: '小明', age: 18 };
res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.end(JSON.stringify(user));
}
});
server.listen(3000);
浏览器访问 http://localhost:3000/api/user,就能看到 {"name":"小明","age":18}。这就是后端接口的雏形,前端用 Axios 请求它就能拿到数据。
🧾 常见状态码速查
| 状态码 | 含义 | 常见场景 |
|---|---|---|
| 200 | 成功 | 正常返回内容 |
| 404 | 未找到 | 地址不存在 |
| 500 | 服务器内部错误 | 代码抛异常了 |
设置方式是 res.statusCode = 404,记得要在 res.end() 之前设置。
🧾 小节总结
- 客户端发请求,服务器返回响应;Node.js 用 http 模块扮演服务器角色。
http.createServer的回调处理每个请求,res.end()必须调用,listen指定端口。- 返回中文要设置
Content-Type: text/plain; charset=utf-8,否则浏览器会乱码。 - 通过
req.url和req.method可以实现简单路由,未匹配的地址返回 404。 - 返回 JSON 接口:
application/json加JSON.stringify。
❓ 知识问答
Q1:res.write 和 res.end 有什么区别?
res.write 可以分多次发送内容,res.end 发送最后的内容并结束响应。简单场景只用 res.end 就够了,每个请求必须有一个 end 收尾。
Q2:改了代码为什么浏览器里不生效?
服务器代码运行在 Node 进程里,改完需要在终端按 Ctrl+C 停止,再重新执行 node server.js。开发时也可以用 node --watch server.js,文件保存后自动重启。
Q3:启动时报端口被占用怎么办?
说明 3000 端口已经被其他程序用了。要么关掉占用它的程序,要么把 listen 的端口换成 3001 等其他值。
Q4:http 模块和 Express 是什么关系?
Express 是基于 http 模块封装的框架,把路由、中间件等常用功能做得更方便。先懂 http 模块的原理,再学 Express 会觉得水到渠成。
🧪 小练习
在服务器上加一个 /api/time 接口,返回当前时间的 JSON,格式为 { "time": "2024-01-01 12:00:00" }。
import http from 'node:http';
const server = http.createServer((req, res) => {
// 请在这里编写代码
});
server.listen(3000);
🎉 恭喜你已经能独立搭建 Web 服务器了!下一篇我们深入 Node.js 的心脏:事件循环与异步机制。
