Node.js: Express 基础
最后更新:2026-08-26
1. 1 从原生 HTTP 到 Express
Alice 用原生 HTTP 模块写了 3 天的 API,代码又长又难维护——手动解析 URL、手写路由匹配、逐行处理请求体。改用 Express 后,同样的功能只用了 30 行代码,路由声明清晰、中间件自动串联,维护效率提升 10 倍。
原生 HTTP vs Express 代码对比
| 对比项 | 原生 HTTP | Express |
|---|---|---|
| 路由定义 | 手动 if/else 匹配 req.url |
声明式 app.get('/path', fn) |
| 请求体解析 | 手动监听 data/end 事件拼 Buffer |
express.json() 一行搞定 |
| 响应发送 | res.writeHead() + res.end() |
res.json() / res.send() |
| 静态文件 | 手动读文件 + 设 Content-Type | express.static('public') |
| 中间件 | 无内置支持 | app.use() 管道式组合 |
| 代码量(同等功能) | ~80 行 | ~30 行 |
- Express 是 Node.js 最流行的 Web 框架,封装了 HTTP 模块的底层细节
- 路由声明式写法让 URL 与处理函数的映射一目了然
- 中间件机制实现关注点分离:日志、鉴权、解析各司其职
- 内置
json()和static()满足 API 开发最常见的两种需求 - 庞大的生态提供海量第三方中间件,开箱即用
2. 2 安装与 Hello World
▶ 示例:(1) 初始化项目与安装 Express
mkdir my-express-app && cd my-express-app
npm init -y
npm install express
▶ 示例:(2) 最小 Hello World
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3000, () => {
console.log('Server running at http://localhost:3000');
});
node app.js
浏览器访问 http://localhost:3000 即可看到 Hello World!。
▶ 示例:返回 JSON 响应
app.get('/api/hello', (req, res) => {
res.json({ message: 'Hello from Express!', status: 'ok' });
});
▶ 示例:带路由参数的 Hello
app.get('/hello/:name', (req, res) => {
res.send(`Hello, ${req.params.name}!`);
});
3. 3 路由方法
Express 路由方法速查
| 方法 | 用途 | 幂等性 | 典型场景 |
|---|---|---|---|
app.get() |
获取资源 | 是 | 查询列表/详情 |
app.post() |
创建资源 | 否 | 提交表单/新增记录 |
app.put() |
全量更新 | 是 | 替换整条记录 |
app.delete() |
删除资源 | 是 | 删除记录 |
app.patch() |
部分更新 | 否 | 修改个别字段 |
app.all() |
匹配所有方法 | — | 通用预处理 |
▶ 示例:(1) RESTful 风格路由
app.get('/users', (req, res) => { res.json({ users: [] }); });
app.post('/users', (req, res) => { res.status(201).json({ created: true }); });
app.put('/users/:id', (req, res) => { res.json({ updated: req.params.id }); });
app.delete('/users/:id', (req, res) => { res.json({ deleted: req.params.id }); });
(2) 路由路径匹配
- 精确匹配:
'/about'仅匹配/about - 参数匹配:
'/users/:id'匹配/users/42,通过req.params.id取值 - 通配匹配:
'/files/*'匹配/files/a/b/c
▶ 示例:查询参数读取
app.get('/search', (req, res) => {
const { q, page = '1' } = req.query;
res.json({ keyword: q, page: Number(page) });
});
▶ 示例:多路由参数
app.get('/posts/:postId/comments/:commentId', (req, res) => {
res.json(req.params);
});
4. 4 中间件概念
Express 的核心设计是中间件管道——每个请求依次流过一系列函数,每个函数可以读取/修改请求与响应,或提前结束请求。
flowchart LR A[请求 Request] --> B[中间件1<br/>日志记录] B --> C[中间件2<br/>JSON解析] C --> D[中间件3<br/>鉴权校验] D --> E[路由处理<br/>业务逻辑] E --> F[响应 Response]
▶ 示例:(1) app.use() 注册中间件
const logger = (req, res, next) => {
console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`);
next();
};
app.use(logger);
(2) 中间件执行顺序
app.use()按注册顺序执行,位置决定逻辑- 调用
next()将控制权交给下一个中间件 - 不调用
next()则请求挂起,必须自行发送响应
▶ 示例:鉴权中间件
const auth = (req, res, next) => {
const token = req.headers['authorization'];
if (!token) return res.status(401).json({ error: 'No token' });
next();
};
app.use('/api', auth);
▶ 示例:错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong!' });
});
5. 5 内置中间件
内置中间件列表
| 中间件 | 用途 | 引入方式 | 常见配置 |
|---|---|---|---|
express.json() |
解析 JSON 请求体 | app.use(express.json()) |
{ limit: '10kb' } |
express.urlencoded() |
解析 URL 编码请求体 | app.use(express.urlencoded({ extended: true })) |
{ extended: true/false } |
express.static() |
托管静态文件 | app.use(express.static('public')) |
{ maxAge: '1d' } |
▶ 示例:(1) express.json() 解析请求体
app.use(express.json());
app.post('/api/users', (req, res) => {
console.log(req.body);
res.json({ received: req.body });
});
(2) express.static() 托管静态文件
假设项目结构:
my-express-app/
├── public/
│ ├── index.html
│ └── style.css
├── app.js
└── package.json
app.use(express.static('public'));
访问 http://localhost:3000/index.html 即可直接加载静态文件。
▶ 示例:多目录静态托管
app.use(express.static('public'));
app.use('/uploads', express.static('uploads'));
▶ 示例:限制 JSON 请求体大小
app.use(express.json({ limit: '100kb' }));
6. 6 nodemon 热重载
nodemon vs node 对比
| 对比项 | node |
nodemon |
|---|---|---|
| 文件变更后 | 手动重启 | 自动重启 |
| 安装方式 | 内置 | npm i -D nodemon |
| 启动命令 | node app.js |
npx nodemon app.js |
| 生产环境 | 适用 | 不适用 |
| 监听目录 | 无 | 默认当前目录,可配置 |
▶ 示例:(1) 安装与使用
npm install --save-dev nodemon
npx nodemon app.js
▶ 示例:(2) package.json 配置脚本
{
"scripts": {
"dev": "nodemon app.js",
"start": "node app.js"
}
}
开发时用 npm run dev(自动重载),生产用 npm start(稳定运行)。
▶ 示例:自定义监听目录
npx nodemon --watch src --ext js,ets app.js
7. 7 综合示例:Express API 应用
将前面所有知识点串联,从零搭建一个完整的小型 API 应用。
const express = require('express');
const app = express();
app.use(express.json());
app.use(express.static('public'));
let todos = [
{ id: 1, task: 'Learn Express', done: false },
{ id: 2, task: 'Build an API', done: false },
];
app.get('/api/todos', (req, res) => res.json(todos));
app.post('/api/todos', (req, res) => {
const todo = { id: todos.length + 1, ...req.body, done: false };
todos.push(todo);
res.status(201).json(todo);
});
app.put('/api/todos/:id', (req, res) => {
const idx = todos.findIndex(t => t.id === Number(req.params.id));
if (idx === -1) return res.status(404).json({ error: 'Not found' });
todos[idx] = { ...todos[idx], ...req.body };
res.json(todos[idx]);
});
app.delete('/api/todos/:id', (req, res) => {
todos = todos.filter(t => t.id !== Number(req.params.id));
res.json({ deleted: true });
});
app.listen(3000, () => console.log('API running at http://localhost:3000'));
启动后即可用浏览器访问静态页面,用 API 工具操作 /api/todos 完成增删改查。
- 安装 Express 后,用
express.json()和express.static()一行搞定请求体解析与静态托管 - RESTful 路由
GET/POST/PUT/DELETE覆盖完整 CRUD - 开发时配合
nodemon修改代码自动生效,无需手动重启
❓ 常见问题
Q: Express 是唯一选择吗? A: 不是,Koa 更轻量、Fastify 更快、Hono 支持边缘运行,但 Express 生态最成熟、学习资源最多,适合入门。
Q: express.json() 必须在路由前调用吗? A: 是的,app.use(express.json()) 必须写在路由之前,否则 req.body 为 undefined,因为中间件按注册顺序执行。
Q: 4.x 和 5.x 有什么区别? A: Express 5.x 移除了已废弃 API(如 app.del),改进了路由匹配(支持 path-to-regexp v8),部分行为变为异步友好,但核心用法基本一致。
Q: 如何自动重启服务? A: 安装 nodemon(npm i -D nodemon),用 npx nodemon app.js 启动,文件保存后自动重启,开发时非常高效。
Q: app.use 和 app.get 有什么区别? A: app.use 匹配所有 HTTP 方法且路径前缀匹配(/api 匹配 /api/anything),app.get 仅匹配 GET 方法且路径精确匹配,前者用于中间件,后者用于路由。
Q: express.urlencoded 的 extended 选项什么意思? A: extended: true 使用 qs 库解析(支持嵌套对象),extended: false 使用 querystring 库(不支持嵌套),一般表单提交用 true 即可。
📖 小节
- 1 从原生 HTTP 到 Express的核心概念与使用方法
- 2 安装与 Hello World的核心概念与使用方法
- 3 路由方法的核心概念与使用方法
- 4 中间件概念的核心概念与使用方法
- 5 内置中间件的核心概念与使用方法
- 6 nodemon 热重载的核心概念与使用方法
- 7 综合示例:Express API 应用的核心概念与使用方法
📝 作业
- 完成本课所有代码示例,确保每个示例都能正确运行
- 修改综合示例,添加自己的扩展功能
- 查阅官方文档,找出本课未涉及的1-2个API并编写测试代码
- 思考:在实际项目中,你会如何应用本课学到的知识?
- 尝试将本课知识与前面课程的内容结合,构建一个小项目