- 路由 (Routing)
- 基本用法 (Basic)
- 路径参数 (Path Parameter)
- 可选参数 (Optional Parameter)
- 正则匹配 (Regexp)
- 包含斜杠 (Including slashes)
- 链式路由 (Chained route)
- 路由分组 (Grouping)
- 不改变 base 的分组 (Grouping without changing base)
- 基础路径 (Base path)
- 按主机名路由 (Routing with hostname)
- 根据 host Header 路由 (Routing with host Header value)
- 路由优先级 (Routing priority)
- 分组顺序 (Grouping ordering)
路由 (Routing)
Hono 的路由非常灵活和直观。让我们来看看。
基本用法 (Basic)
// HTTP 方法app.get('/', (c) => c.text('GET /'))app.post('/', (c) => c.text('POST /'))app.put('/', (c) => c.text('PUT /'))app.delete('/', (c) => c.text('DELETE /'))// 通配符app.get('/wild/*/card', (c) => {return c.text('GET /wild/*/card')})// 匹配所有 HTTP 方法app.all('/hello', (c) => c.text('Any Method /hello'))// 自定义 HTTP 方法app.on('PURGE', '/cache', (c) => c.text('PURGE Method /cache'))// 多个方法app.on(['PUT', 'DELETE'], '/post', (c) =>c.text('PUT or DELETE /post'))// 多个路径app.on('GET', ['/hello', '/ja/hello', '/en/hello'], (c) =>c.text('Hello'))
路径参数 (Path Parameter)
app.get('/user/:name', async (c) => {const name = c.req.param('name')// ...})
或者一次性获取所有参数:
app.get('/posts/:id/comment/:comment_id', async (c) => {const { id, comment_id } = c.req.param()// ...})
可选参数 (Optional Parameter)
// 会同时匹配 `/api/animal` 和 `/api/animal/:type`app.get('/api/animal/:type?', (c) => c.text('Animal!'))
正则匹配 (Regexp)
app.get('/post/:date{[0-9]+}/:title{[a-z]+}', async (c) => {const { date, title } = c.req.param()// ...})
包含斜杠 (Including slashes)
app.get('/posts/:filename{.+\\.png}', async (c) => {//...})
链式路由 (Chained route)
app.get('/endpoint', (c) => {return c.text('GET /endpoint')}).post((c) => {return c.text('POST /endpoint')}).delete((c) => {return c.text('DELETE /endpoint')})
路由分组 (Grouping)
你可以使用 Hono 实例对路由进行分组,然后通过 route 方法添加到主应用。
const book = new Hono()book.get('/', (c) => c.text('List Books')) // GET /bookbook.get('/:id', (c) => {// GET /book/:idconst id = c.req.param('id')return c.text('Get Book: ' + id)})book.post('/', (c) => c.text('Create Book')) // POST /bookconst app = new Hono()app.route('/book', book)
不改变 base 的分组 (Grouping without changing base)
你也可以在不改变 base 路径的情况下分组多个实例。
const book = new Hono()book.get('/book', (c) => c.text('List Books')) // GET /bookbook.post('/book', (c) => c.text('Create Book')) // POST /bookconst user = new Hono().basePath('/user')user.get('/', (c) => c.text('List Users')) // GET /useruser.post('/', (c) => c.text('Create User')) // POST /userconst app = new Hono()app.route('/', book) // 处理 /bookapp.route('/', user) // 处理 /user
基础路径 (Base path)
你可以指定一个基础路径。
const api = new Hono().basePath('/api')api.get('/book', (c) => c.text('List Books')) // GET /api/book
按主机名路由 (Routing with hostname)
当包含主机名时,它也能正常工作。
const app = new Hono({getPath: (req) => req.url.replace(/^https?:\/([^?]+).*$/, '$1'),})app.get('/www1.example.com/hello', (c) => c.text('hello www1'))app.get('/www2.example.com/hello', (c) => c.text('hello www2'))
根据 host Header 路由 (Routing with host Header value)
如果你在 Hono 构造函数中设置了 getPath(),Hono 可以根据 host Header 进行路由。
const app = new Hono({getPath: (req) =>'/' +req.headers.get('host') +req.url.replace(/^https?:\/\/[^/]+(\/[^?]*).*/, '$1'),})app.get('/www1.example.com/hello', (c) => c.text('hello www1'))// 以下请求将匹配上述路由:// new Request('http://www1.example.com/hello', {// headers: { host: 'www1.example.com' },// })
通过这种方式,你还可以根据 User-Agent 等 Header 来改变路由。
路由优先级 (Routing priority)
处理器或中间件会按照注册顺序执行。
app.get('/book/a', (c) => c.text('a')) // aapp.get('/book/:slug', (c) => c.text('common')) // common
GET /book/a ---> `a`GET /book/b ---> `common`
当一个处理器被执行后,流程将会停止。
app.get('*', (c) => c.text('common')) // commonapp.get('/foo', (c) => c.text('foo')) // foo
GET /foo ---> `common` // foo 不会被触发
如果你有必须执行的中间件,请将其写在处理器之前。
app.use(logger())app.get('/foo', (c) => c.text('foo'))
如果你想设置一个 “fallback” 处理器,将其写在其他处理器之后。
app.get('/bar', (c) => c.text('bar')) // barapp.get('*', (c) => c.text('fallback')) // fallback
GET /bar ---> `bar`GET /foo ---> `fallback`
分组顺序 (Grouping ordering)
请注意,路由分组顺序错误可能难以发现。route() 函数会将第二个参数(如 three 或 two)的路由添加到自身(two 或 app)的路由中。
three.get('/hi', (c) => c.text('hi'))two.route('/three', three)app.route('/two', two)export default app
这将返回 200 响应:
GET /two/three/hi ---> `hi`
然而,如果顺序错误,就会返回 404。
three.get('/hi', (c) => c.text('hi'))app.route('/two', two) // `two` 没有任何路由two.route('/three', three)export default app
GET /two/three/hi ---> 404 Not Found
