一、Router配置规则与RESTful风格设计
1. 路由基础配置
Egg.js采用Koa风格的链式路由配置语法,支持多种请求方法:
// app/router.js
module.exports = app => {
const { router, controller } = app;
// 基础路由配置
router.get('/news', controller.news.list);
router.post('/news', controller.news.create);
router.del('/news/:id', controller.news.delete);
// 同时注册多个方法
router.resources('posts', '/api/posts', controller.posts);
};
2. RESTful最佳实践
资源操作 | 请求方法 | 路由示例 | 控制器方法 |
---|---|---|---|
获取列表 | GET | /users | index |
获取单个 | GET | /users/:id | show |
创建资源 | POST | /users | create |
更新全部 | PUT | /users/:id | update |
局部更新 | PATCH | /users/:id | patch |
删除资源 | DELETE | /users/:id | destroy |
推荐使用app.resources
快速生成标准路由:
router.resources('users', '/api/v1/users', controller.v1.users);
3. 特殊路由配置
// 重定向路由
router.redirect('/old', '/new', 302);
// 通配符路由
router.get(/^\/api\/(.*)/, controller.api.proxy);
// 参数约束
router.get('/user/:id(\\d+)', controller.user.detail);
// 路由别名
router.get('userHome', '/user/:name', controller.user.home);
二、控制器(Controller)职责与最佳实践
1. 控制器核心职责
- 输入校验:验证请求参数的合法性
- 流程控制:协调Service层和View层的交互
- 响应处理:返回标准化响应格式
2. 最佳实践示例
// app/controller/user.js
const Controller = require('egg').Controller;
class UserController extends Controller {
async create() {
const { ctx } = this;
// 1. 参数校验
ctx.validate({
username: { type: 'string', required: true },
password: { type: 'password', min: 6 }
});
// 2. 调用Service
const user = await ctx.service.user.create(ctx.request.body);
// 3. 统一响应格式
ctx.success({
code: 201,
data: user,
message: '用户创建成功'
});
}
}
3. 控制器开发规范
- 保持简洁:单个方法不超过50行代码
- 禁止包含:业务逻辑应放在Service层
- 异常处理:统一错误处理中间件捕获异常
- 命名约定:
- 方法名使用RESTful标准动词(index/show/create/update/destroy)
- 文件名为复数形式(users.js)
三、参数传递与响应处理规范
1. 参数获取方式
参数类型 | 获取方式 | 示例 |
---|---|---|
路径参数 | ctx.params | /users/:id → id |
查询参数 | ctx.query | ?name=egg → name |
请求体 | ctx.request.body | POST/PUT请求体 |
头部信息 | ctx.headers | Authorization头 |
Cookie | ctx.cookies.get() | 用户凭证 |
2. 参数校验示例
安装校验插件:
npm install egg-validate --save
控制器中使用:
// 简单校验
ctx.validate({
page: { type: 'int', required: false, default: 1 },
pageSize: { type: 'int', max: 100 }
});
// 自定义校验规则
ctx.validate({
mobile: {
type: 'string',
format: /^1[3-9]\d{9}$/,
message: '手机号格式错误'
}
}, ctx.request.body);
3. 响应处理规范
推荐使用统一响应格式中间件:
// app/middleware/response_formatter.js
module.exports = () => {
return async (ctx, next) => {
try {
await next();
if (ctx.body && !ctx.body.code) {
ctx.body = {
code: 200,
data: ctx.body,
message: 'success'
}
}
} catch (err) {
ctx.status = err.status || 500;
ctx.body = {
code: ctx.status,
message: err.message,
data: null
};
}
};
};
四、路由分组与模块化方案
1. 路由分组实践
// 版本分组
router.namespace('/api/v1', v1 => {
v1.resources('users', '/users', controller.v1.users);
v1.resources('posts', '/posts', controller.v1.posts);
});
router.namespace('/api/v2', v2 => {
v2.resources('users', '/users', controller.v2.users);
});
// 权限分组
const admin = router.namespace('/admin');
admin.get('/dashboard', middleware.authAdmin(), controller.admin.dashboard);
admin.resources('articles', '/articles', controller.admin.articles);
2. 模块化路由方案
创建app/router
目录:
app/router/
├── api.js
├── admin.js
└── web.js
主路由文件加载子路由:
// app/router.js
module.exports = app => {
require('./router/api')(app);
require('./router/admin')(app);
require('./router/web')(app);
};
3. 动态加载路由
// app/router/modules.js
const fs = require('fs');
const path = require('path');
module.exports = app => {
const dir = path.join(app.baseDir, 'app/router/modules');
fs.readdirSync(dir)
.filter(f => f.endsWith('.js'))
.forEach(f => require(path.join(dir, f))(app));
};
五、总结与最佳实践清单
-
路由设计原则:
- 遵循RESTful规范
- 使用动词表示资源操作
- 版本控制通过URL路径实现
-
控制器开发规范:
- 保持单一职责原则
- 参数校验前置处理
- 业务逻辑委托给Service层
-
参数处理建议:
- 敏感参数使用POST请求
- 分页参数统一命名(page/pageSize)
- 响应数据使用DTO转换
-
大型项目路由管理:
- 按业务模块拆分路由文件
- 使用中间件处理通用逻辑
- 定期清理废弃路由
下篇预告:《请求参数处理与数据校验》将深入探讨:
- 多场景参数获取(Query/Params/Body)
- 使用egg-validate进行数据校验
- 文件上传与Stream处理技巧
- 自定义校验规则与错误处理
欢迎在评论区留下你的路由设计经验或遇到的挑战,共同探讨最佳实践!