路由基础 #
一、路由概念 #
1.1 什么是路由? #
路由是指确定应用程序如何响应客户端对特定端点的请求。每个路由可以有一个或多个处理函数,当路由匹配时执行。
1.2 路由结构 #
javascript
app.METHOD(PATH, HANDLER)
| 组成部分 | 说明 |
|---|---|
| app | Express实例 |
| METHOD | HTTP请求方法 |
| PATH | 服务器上的路径 |
| HANDLER | 路由处理函数 |
1.3 基本示例 #
javascript
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('GET请求 - 首页');
});
app.post('/', (req, res) => {
res.send('POST请求 - 首页');
});
app.listen(3000);
二、路由方法 #
2.1 支持的HTTP方法 #
Express支持以下HTTP方法:
| 方法 | 说明 |
|---|---|
| get | 获取资源 |
| post | 创建资源 |
| put | 更新资源(完整更新) |
| patch | 更新资源(部分更新) |
| delete | 删除资源 |
| head | 获取响应头 |
| options | 获取支持的HTTP方法 |
| all | 匹配所有方法 |
2.2 GET请求 #
javascript
app.get('/users', (req, res) => {
res.json({ users: [] });
});
app.get('/users/:id', (req, res) => {
res.json({ id: req.params.id });
});
2.3 POST请求 #
javascript
app.use(express.json());
app.post('/users', (req, res) => {
const user = req.body;
res.status(201).json(user);
});
2.4 PUT请求 #
javascript
app.put('/users/:id', (req, res) => {
const { id } = req.params;
const userData = req.body;
res.json({ id, ...userData, updated: true });
});
2.5 DELETE请求 #
javascript
app.delete('/users/:id', (req, res) => {
res.json({ message: `用户 ${req.params.id} 已删除` });
});
2.6 app.all() #
匹配所有HTTP方法:
javascript
app.all('/secret', (req, res, next) => {
console.log('访问secret路径');
next();
});
app.get('/secret', (req, res) => {
res.send('Secret内容');
});
三、路由路径 #
3.1 字符串路径 #
javascript
app.get('/', (req, res) => {
res.send('根路径');
});
app.get('/about', (req, res) => {
res.send('关于页面');
});
app.get('/random.text', (req, res) => {
res.send('random.text');
});
3.2 字符串模式 #
javascript
app.get('/ab?cd', (req, res) => {
res.send('ab?cd - b可选');
});
app.get('/ab+cd', (req, res) => {
res.send('ab+cd - b可重复');
});
app.get('/ab*cd', (req, res) => {
res.send('ab*cd - 中间任意字符');
});
app.get('/ab(cd)?e', (req, res) => {
res.send('ab(cd)?e - cd可选');
});
3.3 正则表达式 #
javascript
app.get(/a/, (req, res) => {
res.send('包含a的路径');
});
app.get(/.*fly$/, (req, res) => {
res.send('以fly结尾的路径');
});
app.get(/^\/users\/\d+$/, (req, res) => {
res.send('数字用户ID');
});
四、路由参数 #
4.1 路径参数 #
使用 :参数名 定义路径参数:
javascript
app.get('/users/:id', (req, res) => {
res.json({ userId: req.params.id });
});
app.get('/posts/:postId/comments/:commentId', (req, res) => {
res.json({
postId: req.params.postId,
commentId: req.params.commentId
});
});
4.2 可选参数 #
使用 ? 表示可选参数:
javascript
app.get('/users/:id?', (req, res) => {
if (req.params.id) {
res.json({ userId: req.params.id });
} else {
res.json({ users: [] });
}
});
4.3 参数验证 #
使用正则表达式验证参数:
javascript
app.get('/users/:id(\\d+)', (req, res) => {
res.json({ userId: req.params.id });
});
4.4 参数中间件 #
javascript
app.param('id', (req, res, next, id) => {
console.log(`ID参数: ${id}`);
req.user = { id };
next();
});
app.get('/users/:id', (req, res) => {
res.json(req.user);
});
五、查询参数 #
5.1 获取查询参数 #
javascript
app.get('/search', (req, res) => {
const { q, page, limit, sort } = req.query;
res.json({
query: q,
page: parseInt(page) || 1,
limit: parseInt(limit) || 10,
sort: sort || 'desc'
});
});
访问 /search?q=express&page=2&limit=20&sort=asc:
json
{
"query": "express",
"page": 2,
"limit": 20,
"sort": "asc"
}
5.2 处理数组参数 #
javascript
app.get('/filter', (req, res) => {
const { tags } = req.query;
const tagList = Array.isArray(tags) ? tags : [tags].filter(Boolean);
res.json({ tags: tagList });
});
访问 /filter?tags=node&tags=express&tags=javascript:
json
{
"tags": ["node", "express", "javascript"]
}
六、多个处理函数 #
6.1 多个回调函数 #
javascript
app.get('/example', (req, res, next) => {
console.log('第一个处理函数');
next();
}, (req, res) => {
console.log('第二个处理函数');
res.send('响应');
});
6.2 使用数组 #
javascript
const middleware1 = (req, res, next) => {
console.log('中间件1');
next();
};
const middleware2 = (req, res, next) => {
console.log('中间件2');
next();
};
app.get('/protected', [middleware1, middleware2], (req, res) => {
res.send('受保护的内容');
});
6.3 混合使用 #
javascript
app.get('/mixed',
middleware1,
[middleware2, (req, res, next) => {
console.log('中间件3');
next();
}],
(req, res) => {
res.send('混合使用');
}
);
七、响应方法 #
7.1 常用响应方法 #
| 方法 | 说明 |
|---|---|
| res.send() | 发送响应 |
| res.json() | 发送JSON响应 |
| res.status() | 设置状态码 |
| res.redirect() | 重定向 |
| res.render() | 渲染模板 |
| res.sendFile() | 发送文件 |
| res.download() | 下载文件 |
| res.end() | 结束响应 |
7.2 链式调用 #
javascript
app.get('/user', (req, res) => {
res.status(200)
.set('X-Custom-Header', 'value')
.json({ name: 'Express' });
});
7.3 设置响应头 #
javascript
app.get('/headers', (req, res) => {
res.set({
'Content-Type': 'application/json',
'X-Powered-By': 'Express'
});
res.json({ message: 'Headers set' });
});
八、路由组织 #
8.1 按功能分组 #
javascript
const users = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' }
];
app.get('/users', (req, res) => {
res.json(users);
});
app.get('/users/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
res.json(user);
});
app.post('/users', (req, res) => {
const user = { id: users.length + 1, ...req.body };
users.push(user);
res.status(201).json(user);
});
app.put('/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === parseInt(req.params.id));
users[index] = { ...users[index], ...req.body };
res.json(users[index]);
});
app.delete('/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === parseInt(req.params.id));
users.splice(index, 1);
res.status(204).send();
});
8.2 路由链 #
javascript
app.route('/articles')
.get((req, res) => {
res.send('获取文章列表');
})
.post((req, res) => {
res.send('创建文章');
});
app.route('/articles/:id')
.get((req, res) => {
res.send(`获取文章 ${req.params.id}`);
})
.put((req, res) => {
res.send(`更新文章 ${req.params.id}`);
})
.delete((req, res) => {
res.send(`删除文章 ${req.params.id}`);
});
九、路由匹配顺序 #
9.1 匹配规则 #
Express按照定义顺序匹配路由:
javascript
app.get('/users/special', (req, res) => {
res.send('特殊用户');
});
app.get('/users/:id', (req, res) => {
res.send(`用户ID: ${req.params.id}`);
});
访问 /users/special 会匹配第一个路由。
9.2 注意事项 #
javascript
app.get('/users/:id', (req, res) => {
res.send(`用户ID: ${req.params.id}`);
});
app.get('/users/special', (req, res) => {
res.send('特殊用户');
});
此时访问 /users/special 会匹配第一个路由,因为 special 被当作 :id 的值。
9.3 正确顺序 #
javascript
app.get('/users/special', (req, res) => {
res.send('特殊用户');
});
app.get('/users/admin', (req, res) => {
res.send('管理员');
});
app.get('/users/:id', (req, res) => {
res.send(`用户ID: ${req.params.id}`);
});
十、错误处理 #
10.1 同步错误 #
javascript
app.get('/error', (req, res) => {
throw new Error('出错了!');
});
app.use((err, req, res, next) => {
res.status(500).json({ error: err.message });
});
10.2 异步错误 #
javascript
app.get('/async-error', async (req, res, next) => {
try {
const data = await someAsyncFunction();
res.json(data);
} catch (error) {
next(error);
}
});
10.3 404处理 #
javascript
app.get('/', (req, res) => {
res.send('首页');
});
app.use((req, res) => {
res.status(404).json({ error: '路由未找到' });
});
十一、总结 #
路由基础要点:
| 概念 | 说明 |
|---|---|
| 路由结构 | app.METHOD(PATH, HANDLER) |
| HTTP方法 | get、post、put、delete等 |
| 路径模式 | 字符串、正则表达式 |
| 路径参数 | :param定义参数 |
| 查询参数 | req.query获取 |
| 处理函数 | 单个或多个函数 |
下一步,让我们深入学习路由方法!
最后更新:2026-03-28