Skip to content

路由

Hono 的路由灵活且直观。 我们一起来看看。

基础用法

ts
// 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
('任意方法 /hello'))
// 自定义 HTTP 方法
app
.
on
('PURGE', '/cache', (
c
) =>
c
.
text
('PURGE 方法 /cache'))
// 多个方法
app
.
on
(['PUT', 'DELETE'], '/post', (
c
) =>
c
.
text
('PUT 或 DELETE /post')
) // 多个路径
app
.
on
('GET', ['/hello', '/ja/hello', '/en/hello'], (
c
) =>
c
.
text
('你好')
)

路径参数

ts
app
.
get
('/user/:name', async (
c
) => {
const
name
=
c
.
req
.
param
('name')
// ... })

或一次性获取全部参数:

ts
app
.
get
('/posts/:id/comment/:comment_id', async (
c
) => {
const {
id
,
comment_id
} =
c
.
req
.
param
()
// ... })

可选参数

ts
// 将匹配 `/api/animal` 和 `/api/animal/:type`
app
.
get
('/api/animal/:type?', (
c
) =>
c
.
text
('动物!'))

正则表达式

ts
app
.
get
('/post/:date{[0-9]+}/:title{[a-z]+}', async (
c
) => {
const {
date
,
title
} =
c
.
req
.
param
()
// ... })

匹配带斜杠的片段

ts
app
.
get
('/posts/:filename{.+\\.png}', async (
c
) => {
//... })

链式路由

ts
app
.
get
('/endpoint', (
c
) => {
return
c
.
text
('GET /endpoint')
}) .
post
((
c
) => {
return
c
.
text
('POST /endpoint')
}) .
delete
((
c
) => {
return
c
.
text
('DELETE /endpoint')
})

分组

你可以使用另一个 Hono 实例组织路由,再通过 route 方法挂载到主应用。

ts
const 
book
= new
Hono
()
book
.
get
('/', (
c
) =>
c
.
text
('列出书籍')) // GET /book
book
.
get
('/:id', (
c
) => {
// GET /book/:id const
id
=
c
.
req
.
param
('id')
return
c
.
text
('查看书籍:' +
id
)
})
book
.
post
('/', (
c
) =>
c
.
text
('创建书籍')) // POST /book
const
app
= new
Hono
()
app
.
route
('/book',
book
)

不改变基础路径的分组

你也可以在保持原有基础路径的情况下组合多个实例。

ts
const 
book
= new
Hono
()
book
.
get
('/book', (
c
) =>
c
.
text
('列出书籍')) // GET /book
book
.
post
('/book', (
c
) =>
c
.
text
('创建书籍')) // POST /book
const
user
= new
Hono
().
basePath
('/user')
user
.
get
('/', (
c
) =>
c
.
text
('列出用户')) // GET /user
user
.
post
('/', (
c
) =>
c
.
text
('创建用户')) // POST /user
const
app
= new
Hono
()
app
.
route
('/',
book
) // 处理 /book
app
.
route
('/',
user
) // 处理 /user

基础路径

可以为应用指定基础路径。

ts
const 
api
= new
Hono
().
basePath
('/api')
api
.
get
('/book', (
c
) =>
c
.
text
('列出书籍')) // GET /api/book

搭配主机名的路由

在路径中带上主机名也可以正常工作。

ts
const 
app
= new
Hono
({
getPath
: (
req
) =>
req
.
url
.
replace
(/^https?:\/([^?]+).*$/, '$1'),
})
app
.
get
('/www1.example.com/hello', (
c
) =>
c
.
text
('你好 www1'))
app
.
get
('/www2.example.com/hello', (
c
) =>
c
.
text
('你好 www2'))

使用 host 请求头路由

如果在 Hono 构造函数中设置 getPath(),就能利用 host 请求头进行路由判断。

ts
const 
app
= new
Hono
({
getPath
: (
req
) =>
'/' +
req
.
headers
.
get
('host') +
req
.
url
.
replace
(/^https?:\/\/[^/]+(\/[^?]*).*/, '$1'),
})
app
.
get
('/www1.example.com/hello', (
c
) =>
c
.
text
('你好 www1'))
// 以下请求将匹配上面的路由: // new Request('http://www1.example.com/hello', { // headers: { host: 'www1.example.com' }, // })

利用这一点,你甚至可以根据 User-Agent 等请求头调整路由逻辑。

路由优先级

处理函数和中间件会按照注册顺序执行。

ts
app
.
get
('/book/a', (
c
) =>
c
.
text
('a')) // a
app
.
get
('/book/:slug', (
c
) =>
c
.
text
('common')) // common
GET /book/a ---> `a`
GET /book/b ---> `common`

一旦命中了某个处理函数,请求就会停止继续匹配。

ts
app
.
get
('*', (
c
) =>
c
.
text
('common')) // common
app
.
get
('/foo', (
c
) =>
c
.
text
('foo')) // foo
GET /foo ---> `common` // 不会再派发 foo

如果希望中间件优先执行,需要将其写在处理函数之前。

ts
app
.
use
(
logger
())
app
.
get
('/foo', (
c
) =>
c
.
text
('foo'))

若想提供“兜底”处理函数,请将其写在其他处理函数之后。

ts
app
.
get
('/bar', (
c
) =>
c
.
text
('bar')) // bar
app
.
get
('*', (
c
) =>
c
.
text
('fallback')) // fallback
GET /bar ---> `bar`
GET /foo ---> `fallback`

分组顺序

需要注意,分组时顺序错误往往不易察觉。 route() 会把第二个参数(例如 threetwo)中已有的路由加入到自身(twoapp)的路由表中。

ts
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。

ts
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

Released under the MIT License.