Express 框架
Express 是 Node.js 最流行的 Web 框架,提供了一系列强大的功能来帮助快速创建 Web 应用和 API。
快速开始
安装
# 创建项目
mkdir my-express-app
cd my-express-app
# 初始化
npm init -y
# 安装 Express
npm install express
基本应用
const express = require('express');
const app = express();
const PORT = 3000;
// 定义路由
app.get('/', (req, res) => {
res.send('Hello, Express!');
});
// 启动服务器
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`);
});
Express 应用生成器
# 安装生成器
npm install -g express-generator
# 创建项目
express my-app
# 安装依赖
cd my-app
npm install
# 启动
npm start
路由
基本路由
const express = require('express');
const app = express();
// GET 请求
app.get('/', (req, res) => {
res.send('GET 请求');
});
// POST 请求
app.post('/', (req, res) => {
res.send('POST 请求');
});
// PUT 请求
app.put('/', (req, res) => {
res.send('PUT 请求');
});
// DELETE 请求
app.delete('/', (req, res) => {
res.send('DELETE 请求');
});
// 匹配所有 HTTP 方法
app.all('/secret', (req, res) => {
res.send('访问秘密区域');
});
路由参数
// 路径参数
app.get('/users/:id', (req, res) => {
res.send(`用户 ID: ${req.params.id}`);
});
// 多个路径参数
app.get('/users/:userId/books/:bookId', (req, res) => {
res.send(`用户 ${req.params.userId} 的书 ${req.params.bookId}`);
});
// 可选参数
app.get('/users/:id?', (req, res) => {
if (req.params.id) {
res.send(`用户 ID: ${req.params.id}`);
} else {
res.send('所有用户');
}
});
// 正则表达式
app.get('/users/:id(\\d+)', (req, res) => {
res.send(`数字 ID: ${req.params.id}`);
});
查询参数
app.get('/search', (req, res) => {
const { q, page, limit } = req.query;
res.json({
query: q,
page: page || 1,
limit: limit || 10
});
});
// 访问 /search?q=nodejs&page=2
// 响应: { query: "nodejs", page: "2", limit: 10 }
路由方法
// 路由路径可以是字符串模式
app.get('/ab?cd', (req, res) => {
// 匹配 acd 或 abcd
res.send('ab?cd');
});
app.get('/ab+cd', (req, res) => {
// 匹配 abcd, abbcd, abbbcd...
res.send('ab+cd');
});
app.get('/ab*cd', (req, res) => {
// 匹配 abcd, abANYcd, ab123cd...
res.send('ab*cd');
});
app.get('/ab(cd)?e', (req, res) => {
// 匹配 abe 或 abcde
res.send('ab(cd)?e');
});
// 正则表达式路由
app.get(/a/, (req, res) => {
// 匹配任何包含 'a' 的路径
res.send('/a/');
});
中间件
中间件是 Express 的核心概念,用于处理请求和响应。
应用级中间件
const express = require('express');
const app = express();
// 全局中间件
app.use((req, res, next) => {
console.log(`${req.method} ${req.url} - ${new Date().toISOString()}`);
next(); // 调用下一个中间件
});
// 路由级中间件
app.use('/api', (req, res, next) => {
console.log('API 请求');
next();
});
// 错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('服务器错误');
});
内置中间件
const express = require('express');
const app = express();
// 解析 JSON 请求体
app.use(express.json());
// 解析 URL 编码的请求体
app.use(express.urlencoded({ extended: true }));
// 提供静态文件
app.use(express.static('public'));
app.use('/static', express.static('public'));
// 安全相关的中间件
app.use(express.static('public', {
dotfiles: 'ignore',
etag: false,
extensions: ['htm', 'html'],
index: false,
maxAge: '1d',
redirect: false,
setHeaders: function (res, path, stat) {
res.set('x-timestamp', Date.now());
}
}));
路由级中间件
const express = require('express');
const router = express.Router();
// 路由级中间件
router.use((req, res, next) => {
console.log('路由中间件');
next();
});
// 单个路由的中间件
router.get('/user/:id',
(req, res, next) => {
if (req.params.id === '0') next('route');
else next();
},
(req, res) => {
res.send('普通用户');
}
);
router.get('/user/:id', (req, res) => {
res.send('特殊用户');
});
app.use('/api', router);
第三方中间件
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
const compression = require('compression');
const app = express();
// CORS
app.use(cors({
origin: ['https://example.com'],
methods: ['GET', 'POST'],
credentials: true
}));
// 安全头
app.use(helmet());
// 日志
app.use(morgan('combined'));
// 压缩响应
app.use(compression());
请求和响应
Request 对象
app.get('/info', (req, res) => {
res.json({
method: req.method, // 请求方法
url: req.url, // 请求 URL
path: req.path, // 请求路径
query: req.query, // 查询参数
params: req.params, // 路径参数
headers: req.headers, // 请求头
body: req.body, // 请求体(需要解析中间件)
cookies: req.cookies, // Cookies(需要 cookie-parser)
ip: req.ip, // 客户端 IP
protocol: req.protocol, // 协议
hostname: req.hostname, // 主机名
xhr: req.xhr, // 是否 AJAX 请求
});
});
Response 对象
// 发送文本
res.send('Hello');
// 发送 JSON
res.json({ message: '成功' });
// 发送状态码
res.status(201).json({ created: true });
// 发送文件
res.sendFile('/path/to/file.pdf');
// 下载文件
res.download('/path/to/file.pdf', 'report.pdf');
// 重定向
res.redirect('/home');
res.redirect(301, '/new-home');
// 设置响应头
res.set('Content-Type', 'text/plain');
res.set('X-Custom-Header', 'value');
// 设置 Cookie
res.cookie('name', 'value', {
maxAge: 900000,
httpOnly: true
});
// 清除 Cookie
res.clearCookie('name');
// 发送状态码
res.sendStatus(200); // 等同于 res.status(200).send('OK')
res.sendStatus(404); // 等同于 res.status(404).send('Not Found')
路由模块化
创建路由模块
// routes/users.js
const express = require('express');
const router = express.Router();
// 中间件
router.use((req, res, next) => {
console.log('用户路由');
next();
});
// 路由
router.get('/', (req, res) => {
res.json({ users: [] });
});
router.get('/:id', (req, res) => {
res.json({ id: req.params.id });
});
router.post('/', (req, res) => {
res.status(201).json(req.body);
});
module.exports = router;
使用路由模块
// app.js
const express = require('express');
const usersRouter = require('./routes/users');
const postsRouter = require('./routes/posts');
const app = express();
app.use(express.json());
// 挂载路由
app.use('/users', usersRouter);
app.use('/posts', postsRouter);
app.listen(3000);
错误处理
错误处理中间件
const express = require('express');
const app = express();
// 自定义错误类
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
// 404 处理
app.use((req, res, next) => {
next(new AppError(`找不到 ${req.originalUrl}`, 404));
});
// 全局错误处理
app.use((err, req, res, next) => {
err.statusCode = err.statusCode || 500;
err.status = err.status || 'error';
if (process.env.NODE_ENV === 'development') {
res.status(err.statusCode).json({
status: err.status,
error: err,
message: err.message,
stack: err.stack
});
} else {
res.status(err.statusCode).json({
status: err.status,
message: err.message
});
}
});
异步错误处理
// Express 5 自动处理异步错误
app.get('/async', async (req, res, next) => {
const data = await getData(); // 如果抛出错误,自动传递给错误处理
res.json(data);
});
// Express 4 需要手动传递
app.get('/async', async (req, res, next) => {
try {
const data = await getData();
res.json(data);
} catch (err) {
next(err);
}
});
// 或使用包装函数
const catchAsync = (fn) => {
return (req, res, next) => {
fn(req, res, next).catch(next);
};
};
app.get('/async', catchAsync(async (req, res) => {
const data = await getData();
res.json(data);
}));
完整示例
RESTful API
const express = require('express');
const app = express();
// 中间件
app.use(express.json());
// 模拟数据库
let users = [
{ id: 1, name: 'Alice', email: '[email protected]' },
{ id: 2, name: 'Bob', email: '[email protected]' }
];
// 获取所有用户
app.get('/users', (req, res) => {
res.json({ data: users });
});
// 获取单个用户
app.get('/users/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) {
return res.status(404).json({ error: '用户不存在' });
}
res.json({ data: user });
});
// 创建用户
app.post('/users', (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({ error: 'name 和 email 是必填项' });
}
const user = {
id: users.length + 1,
name,
email
};
users.push(user);
res.status(201).json({ data: user });
});
// 更新用户
app.put('/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: '用户不存在' });
}
users[index] = { ...users[index], ...req.body };
res.json({ data: users[index] });
});
// 删除用户
app.delete('/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: '用户不存在' });
}
users.splice(index, 1);
res.status(204).send();
});
// 错误处理
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: '服务器错误' });
});
app.listen(3000, () => {
console.log('服务器运行在 http://localhost:3000');
});
小结
本章我们学习了:
- Express 基础:安装、创建应用、路由定义
- 路由:路径参数、查询参数、路由方法
- 中间件:应用级、路由级、内置中间件
- 请求响应:Request 和 Response 对象
- 路由模块化:拆分路由文件
- 错误处理:自定义错误、异步错误
练习
- 创建一个完整的 RESTful API,包含 CRUD 操作
- 实现用户认证中间件(JWT)
- 创建一个文件上传接口
- 实现请求日志和错误追踪