路由前缀的配置方法
路由前缀的配置方法
Koa2中路由前缀的配置能有效组织API结构,特别是在大型项目中。通过给路由添加统一前缀,可以减少重复代码并提升可维护性。下面详细介绍几种常见实现方式。
使用koa-router的prefix方法
koa-router
的prefix
方法是最直接的配置方式。新建路由实例时传入prefix
参数,该路由下的所有路径都会自动添加指定前缀:
const Router = require('koa-router')
const router = new Router({
prefix: '/api/v1' // 全局前缀
})
router.get('/users', ctx => {
ctx.body = '用户列表' // 实际路径是/api/v1/users
})
router.post('/articles', ctx => {
ctx.body = '创建文章' // 实际路径是/api/v1/articles
})
嵌套路由实现多级前缀
对于需要多级前缀的场景,可以通过嵌套路由实现:
const apiRouter = new Router({ prefix: '/api' })
const v1Router = new Router({ prefix: '/v1' })
v1Router.get('/products', ctx => {
ctx.body = '产品列表' // 完整路径/api/v1/products
})
apiRouter.use(v1Router.routes())
动态前缀配置
有时需要根据运行环境动态设置前缀,可以通过函数形式实现:
const envPrefix = process.env.NODE_ENV === 'development' ? '/dev' : '/prod'
const dynamicRouter = new Router({
prefix: `/api${envPrefix}`
})
dynamicRouter.get('/config', ctx => {
ctx.body = `当前环境配置` // 开发环境路径为/api/dev/config
})
多路由实例合并
当项目中有多个模块需要不同前缀时,可以创建多个路由实例:
const adminRouter = new Router({ prefix: '/admin' })
const clientRouter = new Router({ prefix: '/client' })
adminRouter.get('/dashboard', ctx => {
ctx.body = '管理后台'
})
clientRouter.get('/home', ctx => {
ctx.body = '客户端首页'
})
// 合并路由
app.use(adminRouter.routes())
app.use(clientRouter.routes())
路径参数与前缀结合使用
路由前缀可以与路径参数协同工作:
const projectRouter = new Router({
prefix: '/projects/:projectId'
})
projectRouter.get('/tasks', ctx => {
// 访问/projects/123/tasks时
ctx.body = `项目${ctx.params.projectId}的任务列表`
})
中间件对前缀路由的影响
需要注意中间件的执行顺序会影响前缀路由:
app.use(async (ctx, next) => {
console.log('全局中间件')
await next()
})
const authRouter = new Router({ prefix: '/secure' })
authRouter.use(async (ctx, next) => {
console.log('路由级中间件')
await next()
})
// 访问/secure/test时,会先执行全局中间件再执行路由中间件
反向代理场景下的前缀处理
当Koa应用部署在反向代理后时,可能需要处理额外前缀:
const proxy = require('koa-proxies')
const mount = require('koa-mount')
const apiApp = new Koa()
const apiRouter = new Router()
apiRouter.get('/data', ctx => { ctx.body = 'API数据' })
apiApp.use(apiRouter.routes())
// 主应用中将API挂载到特定前缀下
app.use(mount('/external-api', apiApp))
自定义前缀生成函数
对于复杂场景,可以封装前缀生成逻辑:
function createPrefixedRouter(moduleName) {
return new Router({
prefix: `/modules/${moduleName}/v${moduleVersion(moduleName)}`
})
}
function moduleVersion(name) {
const versions = { user: 2, product: 1 }
return versions[name] || 1
}
const userRouter = createPrefixedRouter('user')
userRouter.get('/profile', ctx => {
// 路径为/modules/user/v2/profile
})
测试时的前缀处理
在测试环境中可能需要临时修改前缀:
describe('路由测试', () => {
let testRouter
beforeEach(() => {
testRouter = new Router({ prefix: '/test' })
testRouter.get('/example', ctx => { ctx.body = '测试用例' })
})
it('应该响应测试前缀', async () => {
const res = await request(app.callback())
.get('/test/example')
expect(res.status).to.equal(200)
})
})
常见问题与解决方案
- 前缀冲突:多个路由使用相同前缀时,注意定义顺序
// 错误示例:模糊路径在前会拦截具体路径
router.get('/users/:id', handler1)
router.get('/users/all', handler2) // 永远不会执行
// 正确顺序
router.get('/users/all', handler2)
router.get('/users/:id', handler1)
- 前缀重定向:需要处理带/和不带/的路径差异
router.get('/admin', ctx => {
ctx.redirect('/admin/') // 统一格式
})
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:路由分组与模块化组织
下一篇:路由级别的中间件应用