路由基础 #
一、路由概念 #
1.1 什么是路由? #
路由是指确定应用程序如何响应客户端对特定端点的请求。Hapi使用配置对象的方式定义路由,代码更清晰、可维护。
1.2 路由结构 #
javascript
server.route({
method: 'GET',
path: '/hello',
handler: (request, h) => {
return 'Hello!';
}
});
| 组成部分 | 说明 |
|---|---|
| method | HTTP请求方法 |
| path | URL路径 |
| handler | 处理函数 |
| options | 配置选项(可选) |
1.3 基本示例 #
javascript
const Hapi = require('@hapi/hapi');
const init = async () => {
const server = Hapi.server({ port: 3000 });
server.route({
method: 'GET',
path: '/',
handler: (request, h) => {
return 'Hello World';
}
});
await server.start();
};
init();
二、路由定义方式 #
2.1 单个路由 #
javascript
server.route({
method: 'GET',
path: '/users',
handler: (request, h) => {
return { users: [] };
}
});
2.2 多个路由 #
使用数组定义多个路由:
javascript
server.route([
{
method: 'GET',
path: '/users',
handler: (request, h) => {
return { users: [] };
}
},
{
method: 'POST',
path: '/users',
handler: (request, h) => {
return { message: 'User created' };
}
},
{
method: 'GET',
path: '/users/{id}',
handler: (request, h) => {
return { id: request.params.id };
}
}
]);
2.3 路由配置选项 #
javascript
server.route({
method: 'POST',
path: '/users',
options: {
description: '创建新用户',
notes: '需要管理员权限',
tags: ['api', 'users'],
auth: 'jwt',
validate: {
payload: Joi.object({
name: Joi.string().required(),
email: Joi.string().email().required()
})
},
response: {
schema: Joi.object({
id: Joi.number(),
name: Joi.string(),
email: Joi.string()
})
}
},
handler: createUser
});
三、路径匹配 #
3.1 静态路径 #
javascript
server.route({
method: 'GET',
path: '/about',
handler: (request, h) => {
return 'About Page';
}
});
3.2 路径参数 #
使用 {param} 定义路径参数:
javascript
server.route({
method: 'GET',
path: '/users/{id}',
handler: (request, h) => {
return `User ID: ${request.params.id}`;
}
});
3.3 可选参数 #
使用 {param?} 定义可选参数:
javascript
server.route({
method: 'GET',
path: '/users/{id?}',
handler: (request, h) => {
if (request.params.id) {
return `User ID: ${request.params.id}`;
}
return 'All Users';
}
});
3.4 多段参数 #
使用 {param*} 匹配多段路径:
javascript
server.route({
method: 'GET',
path: '/files/{path*}',
handler: (request, h) => {
return `File path: ${request.params.path}`;
}
});
访问 /files/docs/api/users 返回 File path: docs/api/users
3.5 参数数量限制 #
javascript
server.route({
method: 'GET',
path: '/files/{path*2}',
handler: (request, h) => {
return `Path: ${request.params.path}`;
}
});
只能匹配两段路径,如 /files/docs/api
四、路径参数验证 #
4.1 参数验证 #
javascript
const Joi = require('joi');
server.route({
method: 'GET',
path: '/users/{id}',
options: {
validate: {
params: Joi.object({
id: Joi.number().integer().positive().required()
})
}
},
handler: (request, h) => {
return { userId: request.params.id };
}
});
4.2 正则验证 #
javascript
server.route({
method: 'GET',
path: '/users/{id}',
options: {
validate: {
params: Joi.object({
id: Joi.string().regex(/^[a-zA-Z0-9]+$/)
})
}
},
handler: (request, h) => {
return { userId: request.params.id };
}
});
五、查询参数 #
5.1 获取查询参数 #
javascript
server.route({
method: 'GET',
path: '/search',
handler: (request, h) => {
const { q, page, limit } = request.query;
return {
query: q,
page: page || 1,
limit: limit || 10
};
}
});
访问 /search?q=hapi&page=2&limit=20
5.2 查询参数验证 #
javascript
server.route({
method: 'GET',
path: '/search',
options: {
validate: {
query: Joi.object({
q: Joi.string().required(),
page: Joi.number().integer().min(1).default(1),
limit: Joi.number().integer().min(1).max(100).default(10)
})
}
},
handler: (request, h) => {
return request.query;
}
});
5.3 数组查询参数 #
javascript
server.route({
method: 'GET',
path: '/filter',
options: {
validate: {
query: Joi.object({
tags: Joi.array().items(Joi.string()).single()
})
}
},
handler: (request, h) => {
return { tags: request.query.tags };
}
});
访问 /filter?tags=node&tags=hapi
六、路由选项 #
6.1 常用选项 #
javascript
server.route({
method: 'POST',
path: '/users',
options: {
description: '创建用户',
notes: '创建一个新的用户账户',
tags: ['api'],
auth: false,
cors: true,
timeout: {
server: 30000
},
payload: {
maxBytes: 1048576,
parse: true
}
},
handler: (request, h) => {
return request.payload;
}
});
6.2 认证配置 #
javascript
server.route({
method: 'GET',
path: '/profile',
options: {
auth: 'jwt',
description: '获取用户资料'
},
handler: (request, h) => {
return { user: request.auth.credentials };
}
});
6.3 CORS配置 #
javascript
server.route({
method: 'GET',
path: '/api/data',
options: {
cors: {
origin: ['https://example.com'],
headers: ['Accept', 'Content-Type'],
additionalHeaders: ['X-Custom-Header']
}
},
handler: (request, h) => {
return { data: 'value' };
}
});
6.4 文件上传配置 #
javascript
server.route({
method: 'POST',
path: '/upload',
options: {
payload: {
output: 'file',
parse: true,
maxBytes: 10 * 1024 * 1024,
multipart: true
}
},
handler: (request, h) => {
const file = request.payload.file;
return { filename: file.filename };
}
});
七、路由前缀 #
7.1 服务器级别前缀 #
javascript
const server = Hapi.server({
port: 3000,
routes: {
prefix: '/api'
}
});
server.route({
method: 'GET',
path: '/users',
handler: (request, h) => {
return 'Users';
}
});
实际路径为 /api/users
7.2 插件级别前缀 #
javascript
await server.register({
plugin: myPlugin,
options: {},
routes: {
prefix: '/v1'
}
});
八、路由匹配顺序 #
8.1 匹配规则 #
Hapi按照定义顺序匹配路由,更具体的路由应该放在前面:
javascript
server.route([
{
method: 'GET',
path: '/users/admin',
handler: (request, h) => {
return 'Admin User';
}
},
{
method: 'GET',
path: '/users/{id}',
handler: (request, h) => {
return `User: ${request.params.id}`;
}
}
]);
8.2 路由冲突 #
避免路由冲突:
javascript
server.route([
{
method: 'GET',
path: '/users/{id}',
handler: getUserById
},
{
method: 'GET',
path: '/users/profile',
handler: getProfile
}
]);
访问 /users/profile 会匹配第一个路由,profile 被当作 id。
正确顺序:
javascript
server.route([
{
method: 'GET',
path: '/users/profile',
handler: getProfile
},
{
method: 'GET',
path: '/users/{id}',
handler: getUserById
}
]);
九、路由默认值 #
9.1 默认处理 #
javascript
server.route({
method: 'GET',
path: '/{any*}',
handler: (request, h) => {
return h.response({ error: 'Not Found' }).code(404);
}
});
9.2 默认验证失败处理 #
javascript
const server = Hapi.server({
port: 3000,
routes: {
validate: {
failAction: (request, h, err) => {
console.error(err);
throw err;
}
}
}
});
十、路由分组 #
10.1 按功能分组 #
javascript
const userRoutes = [
{
method: 'GET',
path: '/users',
handler: getUsers
},
{
method: 'GET',
path: '/users/{id}',
handler: getUser
},
{
method: 'POST',
path: '/users',
handler: createUser
}
];
const productRoutes = [
{
method: 'GET',
path: '/products',
handler: getProducts
},
{
method: 'POST',
path: '/products',
handler: createProduct
}
];
server.route([...userRoutes, ...productRoutes]);
10.2 模块化路由 #
routes/users.js:
javascript
const handlers = require('../handlers/users');
module.exports = [
{
method: 'GET',
path: '/users',
handler: handlers.getAll
},
{
method: 'POST',
path: '/users',
handler: handlers.create
}
];
routes/index.js:
javascript
const userRoutes = require('./users');
const productRoutes = require('./products');
module.exports = [
...userRoutes,
...productRoutes
];
十一、总结 #
路由基础要点:
| 概念 | 说明 |
|---|---|
| 路由结构 | method, path, handler, options |
| 路径参数 | {param} 定义参数 |
| 可选参数 | {param?} 可选 |
| 多段参数 | {param*} 多段匹配 |
| 查询参数 | request.query 获取 |
| 验证 | validate 选项配置 |
下一步,让我们深入学习路由方法!
最后更新:2026-03-28