外观
Express 笔记
约 1738 字大约 6 分钟
2025-08-16
一、Express 基础
1.1 什么是 Express?
Express 是基于 Node.js 平台的快速、开放、极简的 Web 开发框架。它简化了创建 Web 服务器和 API 接口的过程,让你能更专注于业务逻辑而非底层实现。
Express 的核心价值:
- 提供简洁的 API 来处理 HTTP 请求
- 支持中间件架构,可灵活扩展功能
- 轻量级但功能强大,适合构建各种规模的应用
- 拥有庞大的生态系统和社区支持
1.2 Express 能做什么?
- Web 网站服务器:提供 HTML 页面和静态资源
- API 接口服务器:构建 RESTful API 供前端或移动端调用
- 单页应用服务器:结合前端框架(React、Vue 等)提供服务
- 代理服务器:处理请求转发和跨域问题
1.3 安装与基本使用
安装 Express
npm init -y
npm install express创建基本服务器
// 1. 导入 express
const express = require('express');
// 2. 创建 web 服务器实例
const app = express();
// 3. 启动服务器
app.listen(3000, () => {
console.log('Express 服务器运行在 http://127.0.0.1:3000');
});监听 GET 请求
app.get('/', (req, res) => {
res.send('首页');
});
app.get('/about', (req, res) => {
res.send('关于页面');
});监听 POST 请求
app.post('/login', (req, res) => {
res.send('登录成功');
});二、路由系统
2.1 路由基础
路由的概念 路由是客户端请求与服务器处理函数之间的映射关系,由三部分组成:
- 请求类型(GET、POST 等)
- 请求 URL 地址
- 处理函数
基本路由语法
// 匹配 GET 请求,且请求 URL 为 /
app.get('/', (req, res) => {
res.send('Hello World!');
});
// 匹配 POST 请求,且请求 URL 为 /submit
app.post('/submit', (req, res) => {
res.send('提交成功');
});路由匹配过程
- 按照定义的先后顺序进行匹配
- 请求类型和 URL 同时匹配成功,才会调用对应的处理函数
- 匹配成功后,后续路由不再检查
2.2 路由参数
动态路由参数
// URL 中通过 :参数名 匹配动态参数值
app.get('/users/:id', (req, res) => {
// req.params 是一个对象,包含所有动态参数
res.send(`用户ID: ${req.params.id}`);
});
// 可以有多个动态参数
app.get('/users/:id/posts/:postId', (req, res) => {
res.send(`用户ID: ${req.params.id}, 帖子ID: ${req.params.postId}`);
});查询参数
// 获取 URL 中的查询参数(? 后面的部分)
app.get('/search', (req, res) => {
// req.query 是一个对象,包含所有查询参数
res.send(`搜索关键词: ${req.query.q}`);
});
// 示例:/search?q=nodejs&page=22.3 模块化路由
创建路由模块
// routes/users.js
const express = require('express');
const router = express.Router();
// 定义路由
router.get('/', (req, res) => {
res.send('用户列表');
});
router.get('/:id', (req, res) => {
res.send(`用户详情: ${req.params.id}`);
});
router.post('/', (req, res) => {
res.send('创建用户');
});
module.exports = router;注册路由模块
// app.js
const usersRouter = require('./routes/users');
// 注册路由模块,添加统一前缀
app.use('/api/users', usersRouter);路由模块的优势:
- 代码组织更清晰
- 便于维护和扩展
- 不同功能模块可以独立开发
三、中间件
3.1 什么是中间件?
中间件是 Express 应用的核心,它是在请求和响应周期中被调用的函数,可以访问请求对象(req)、响应对象(res)和下一个中间件函数(next)。
中间件的作用:
- 执行任何代码
- 修改请求和响应对象
- 终结请求-响应周期
- 调用堆栈中的下一个中间件
3.2 中间件类型
应用级别中间件
// 全局中间件 - 对所有请求生效
app.use((req, res, next) => {
console.log('请求时间:', Date.now());
next(); // 传递到下一个中间件
});
// 路由特定中间件
app.use('/api', (req, res, next) => {
console.log('API 请求');
next();
});路由级别中间件
const router = express.Router();
router.use((req, res, next) => {
console.log('用户路由中间件');
next();
});
router.get('/', (req, res) => {
res.send('用户列表');
});
app.use('/users', router);错误处理中间件
// 必须有 4 个参数:err, req, res, next
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('服务器内部错误');
});3.3 内置中间件
静态资源托管
// 托管 public 目录下的静态资源
app.use(express.static('public'));
// 可以指定虚拟路径前缀
app.use('/static', express.static('public'));现在可以访问:http://localhost:3000/images/logo.png
JSON 请求体解析
// 解析 application/json 格式的数据
app.use(express.json());URL 编码请求体解析
// 解析 application/x-www-form-urlencoded 格式的数据
app.use(express.urlencoded({ extended: false }));配置后,可以通过 req.body 获取表单数据
3.4 中间件使用技巧
中间件执行顺序
// 1. 日志中间件
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});
// 2. 身份验证中间件
app.use((req, res, next) => {
if (req.query.token === 'secret') {
next();
} else {
res.status(401).send('未授权');
}
});
// 3. 业务逻辑
app.get('/protected', (req, res) => {
res.send('受保护的资源');
});条件中间件
// 根据条件应用中间件
const conditionalMiddleware = (req, res, next) => {
if (req.query.debug === 'true') {
console.log('调试模式开启');
}
next();
};
app.use(conditionalMiddleware);四、请求与响应处理
4.1 请求对象 (req)
常用属性:
req.params:获取路由参数req.query:获取查询参数req.body:获取请求体数据(需要配置解析中间件)req.headers:获取请求头req.ip:获取客户端 IP 地址
示例:
app.post('/login', (req, res) => {
const { username, password } = req.body;
// 处理登录逻辑
});4.2 响应对象 (res)
常用方法:
res.send():发送响应数据(自动设置 Content-Type)res.json():发送 JSON 响应res.status():设置 HTTP 状态码res.sendFile():发送文件res.redirect():重定向res.render():渲染视图(需要配置模板引擎)
示例:
// 发送 JSON 响应
app.get('/api/users', (req, res) => {
res.json({ users: [{ id: 1, name: 'John' }] });
});
// 重定向
app.get('/old-page', (req, res) => {
res.redirect('/new-page');
});
// 发送文件
app.get('/download', (req, res) => {
res.sendFile(__dirname + '/file.pdf');
});五、实用技巧与最佳实践
5.1 开发环境优化
使用 nodemon 自动重启
# 全局安装
npm install -g nodemon
# 启动应用
nodemon app.js代码修改后自动重启服务器,提高开发效率
5.2 RESTful API 设计
RESTful 路由示例:
// 获取所有资源
app.get('/api/posts', (req, res) => { ... });
// 创建新资源
app.post('/api/posts', (req, res) => { ... });
// 获取单个资源
app.get('/api/posts/:id', (req, res) => { ... });
// 更新资源
app.put('/api/posts/:id', (req, res) => { ... });
// 部分更新资源
app.patch('/api/posts/:id', (req, res) => { ... });
// 删除资源
app.delete('/api/posts/:id', (req, res) => { ... });状态码使用规范:
200 OK:成功获取资源201 Created:成功创建资源204 No Content:成功处理但无内容返回400 Bad Request:客户端请求错误401 Unauthorized:未认证403 Forbidden:无权限404 Not Found:资源不存在500 Internal Server Error:服务器内部错误
5.3 错误处理
统一错误处理中间件
// 业务逻辑中抛出错误
app.get('/error', (req, res, next) => {
try {
// 可能出错的代码
throw new Error('测试错误');
} catch (err) {
next(err);
}
});
// 统一错误处理
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
success: false,
message: '服务器内部错误',
error: process.env.NODE_ENV === 'development' ? err.message : {}
});
});5.4 环境变量管理
使用 dotenv 管理环境变量
npm install dotenv// 在应用最开始加载
require('dotenv').config();
// 使用环境变量
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`服务器运行在端口 ${port}`);
});.env 文件示例
PORT=3000
DB_HOST=localhost
DB_USER=root
DB_PASS=secret