路由方法 #
一、HTTP方法概述 #
1.1 RESTful API设计 #
| HTTP方法 | CRUD操作 | 说明 |
|---|---|---|
| GET | Read | 获取资源 |
| POST | Create | 创建资源 |
| PUT | Update | 完整更新资源 |
| PATCH | Update | 部分更新资源 |
| DELETE | Delete | 删除资源 |
1.2 Express支持的方法 #
javascript
app.get()
app.post()
app.put()
app.patch()
app.delete()
app.head()
app.options()
app.all()
二、GET方法 #
2.1 基本用法 #
GET方法用于获取资源:
javascript
app.get('/users', (req, res) => {
res.json({ users: [] });
});
2.2 获取单个资源 #
javascript
app.get('/users/:id', (req, res) => {
const { id } = req.params;
res.json({ id, name: '用户名' });
});
2.3 带查询参数 #
javascript
app.get('/users', (req, res) => {
const { page = 1, limit = 10, sort = 'desc' } = req.query;
res.json({
page: parseInt(page),
limit: parseInt(limit),
sort,
users: []
});
});
2.4 条件查询 #
javascript
app.get('/products', (req, res) => {
const { category, minPrice, maxPrice, inStock } = req.query;
const filters = {};
if (category) filters.category = category;
if (minPrice) filters.minPrice = parseFloat(minPrice);
if (maxPrice) filters.maxPrice = parseFloat(maxPrice);
if (inStock) filters.inStock = inStock === 'true';
res.json({ filters, products: [] });
});
2.5 分页示例 #
javascript
const users = Array.from({ length: 100 }, (_, i) => ({
id: i + 1,
name: `用户${i + 1}`
}));
app.get('/users', (req, res) => {
const page = parseInt(req.query.page) || 1;
const limit = parseInt(req.query.limit) || 10;
const skip = (page - 1) * limit;
const paginatedUsers = users.slice(skip, skip + limit);
res.json({
page,
limit,
total: users.length,
totalPages: Math.ceil(users.length / limit),
data: paginatedUsers
});
});
三、POST方法 #
3.1 基本用法 #
POST方法用于创建资源:
javascript
app.use(express.json());
app.post('/users', (req, res) => {
const { name, email } = req.body;
const newUser = {
id: Date.now(),
name,
email,
createdAt: new Date()
};
res.status(201).json(newUser);
});
3.2 表单数据处理 #
javascript
app.use(express.urlencoded({ extended: true }));
app.post('/login', (req, res) => {
const { username, password } = req.body;
if (username === 'admin' && password === '123456') {
res.json({ success: true, message: '登录成功' });
} else {
res.status(401).json({ success: false, message: '用户名或密码错误' });
}
});
3.3 文件上传 #
javascript
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
app.post('/upload', upload.single('file'), (req, res) => {
res.json({
message: '文件上传成功',
file: req.file
});
});
app.post('/photos', upload.array('photos', 5), (req, res) => {
res.json({
message: '多文件上传成功',
files: req.files
});
});
3.4 数据验证 #
javascript
app.post('/users', (req, res) => {
const { name, email, password } = req.body;
if (!name || !email || !password) {
return res.status(400).json({
error: '请填写所有必填字段'
});
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
return res.status(400).json({
error: '请输入有效的邮箱地址'
});
}
if (password.length < 6) {
return res.status(400).json({
error: '密码至少6个字符'
});
}
res.status(201).json({ name, email });
});
四、PUT方法 #
4.1 基本用法 #
PUT方法用于完整更新资源:
javascript
app.put('/users/:id', (req, res) => {
const { id } = req.params;
const { name, email, age } = req.body;
const updatedUser = {
id: parseInt(id),
name,
email,
age,
updatedAt: new Date()
};
res.json(updatedUser);
});
4.2 完整替换 #
javascript
let users = [
{ id: 1, name: '张三', email: 'zhangsan@example.com' },
{ id: 2, name: '李四', email: 'lisi@example.com' }
];
app.put('/users/:id', (req, res) => {
const { id } = req.params;
const index = users.findIndex(u => u.id === parseInt(id));
if (index === -1) {
return res.status(404).json({ error: '用户不存在' });
}
users[index] = {
id: parseInt(id),
...req.body,
updatedAt: new Date()
};
res.json(users[index]);
});
五、PATCH方法 #
5.1 基本用法 #
PATCH方法用于部分更新资源:
javascript
app.patch('/users/:id', (req, res) => {
const { id } = req.params;
const updates = req.body;
res.json({
id: parseInt(id),
...updates,
updatedAt: new Date()
});
});
5.2 部分更新示例 #
javascript
let users = [
{ id: 1, name: '张三', email: 'zhangsan@example.com', age: 25 },
{ id: 2, name: '李四', email: 'lisi@example.com', age: 30 }
];
app.patch('/users/:id', (req, res) => {
const { id } = req.params;
const index = users.findIndex(u => u.id === parseInt(id));
if (index === -1) {
return res.status(404).json({ error: '用户不存在' });
}
const allowedUpdates = ['name', 'email', 'age'];
const updates = Object.keys(req.body);
const isValid = updates.every(update => allowedUpdates.includes(update));
if (!isValid) {
return res.status(400).json({ error: '无效的更新字段' });
}
users[index] = {
...users[index],
...req.body,
updatedAt: new Date()
};
res.json(users[index]);
});
六、DELETE方法 #
6.1 基本用法 #
DELETE方法用于删除资源:
javascript
app.delete('/users/:id', (req, res) => {
const { id } = req.params;
res.status(204).send();
});
6.2 返回被删除的资源 #
javascript
let users = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' }
];
app.delete('/users/:id', (req, res) => {
const { id } = req.params;
const index = users.findIndex(u => u.id === parseInt(id));
if (index === -1) {
return res.status(404).json({ error: '用户不存在' });
}
const deletedUser = users.splice(index, 1)[0];
res.json({
message: '删除成功',
user: deletedUser
});
});
6.3 批量删除 #
javascript
app.delete('/users', (req, res) => {
const { ids } = req.body;
if (!Array.isArray(ids)) {
return res.status(400).json({ error: 'ids必须是数组' });
}
res.json({
message: '批量删除成功',
count: ids.length
});
});
七、HEAD方法 #
7.1 基本用法 #
HEAD方法只返回响应头,不返回响应体:
javascript
app.head('/users', (req, res) => {
res.set('X-Total-Count', '100');
res.end();
});
7.2 检查资源是否存在 #
javascript
app.head('/files/:filename', (req, res) => {
const { filename } = req.params;
if (fileExists(filename)) {
res.set('Content-Type', 'application/pdf');
res.set('Content-Length', getFileSize(filename));
res.status(200).end();
} else {
res.status(404).end();
}
});
八、OPTIONS方法 #
8.1 基本用法 #
OPTIONS方法返回服务器支持的方法:
javascript
app.options('/users', (req, res) => {
res.set('Allow', 'GET, POST, PUT, DELETE');
res.end();
});
8.2 CORS预检请求 #
javascript
app.options('/api/*', (req, res) => {
res.set({
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '86400'
});
res.end();
});
九、app.all() #
9.1 匹配所有方法 #
javascript
app.all('/api/*', (req, res, next) => {
console.log(`${req.method} ${req.path}`);
next();
});
9.2 认证保护 #
javascript
app.all('/admin/*', (req, res, next) => {
if (!req.user || req.user.role !== 'admin') {
return res.status(403).json({ error: '需要管理员权限' });
}
next();
});
9.3 日志记录 #
javascript
app.all('*', (req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
next();
});
十、app.route() #
10.1 链式路由 #
javascript
app.route('/articles')
.get((req, res) => {
res.json({ articles: [] });
})
.post((req, res) => {
res.status(201).json(req.body);
});
app.route('/articles/:id')
.get((req, res) => {
res.json({ id: req.params.id });
})
.put((req, res) => {
res.json({ id: req.params.id, ...req.body });
})
.delete((req, res) => {
res.status(204).send();
});
10.2 完整CRUD示例 #
javascript
let articles = [];
app.route('/articles')
.get((req, res) => {
res.json(articles);
})
.post((req, res) => {
const article = {
id: articles.length + 1,
...req.body,
createdAt: new Date()
};
articles.push(article);
res.status(201).json(article);
});
app.route('/articles/:id')
.get((req, res) => {
const article = articles.find(a => a.id === parseInt(req.params.id));
if (!article) {
return res.status(404).json({ error: '文章不存在' });
}
res.json(article);
})
.put((req, res) => {
const index = articles.findIndex(a => a.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: '文章不存在' });
}
articles[index] = {
...articles[index],
...req.body,
updatedAt: new Date()
};
res.json(articles[index]);
})
.delete((req, res) => {
const index = articles.findIndex(a => a.id === parseInt(req.params.id));
if (index === -1) {
return res.status(404).json({ error: '文章不存在' });
}
articles.splice(index, 1);
res.status(204).send();
});
十一、RESTful最佳实践 #
11.1 资源命名 #
| 好的设计 | 不好的设计 |
|---|---|
| GET /users | GET /getUsers |
| POST /users | POST /createUser |
| PUT /users/:id | PUT /updateUser/:id |
| DELETE /users/:id | DELETE /deleteUser/:id |
11.2 状态码使用 #
| 状态码 | 说明 | 使用场景 |
|---|---|---|
| 200 | 成功 | GET、PUT、PATCH |
| 201 | 创建成功 | POST |
| 204 | 无内容 | DELETE |
| 400 | 错误请求 | 参数验证失败 |
| 401 | 未认证 | 需要登录 |
| 403 | 禁止访问 | 无权限 |
| 404 | 未找到 | 资源不存在 |
| 500 | 服务器错误 | 程序错误 |
11.3 响应格式 #
成功响应:
javascript
res.json({
success: true,
data: { },
message: '操作成功'
});
错误响应:
javascript
res.status(400).json({
success: false,
error: '错误信息',
code: 'ERROR_CODE'
});
十二、总结 #
路由方法要点:
| 方法 | 用途 | 幂等性 |
|---|---|---|
| GET | 获取资源 | 是 |
| POST | 创建资源 | 否 |
| PUT | 完整更新 | 是 |
| PATCH | 部分更新 | 否 |
| DELETE | 删除资源 | 是 |
下一步,让我们学习路由参数!
最后更新:2026-03-28