Appearance
路由
¥Routing
Hono 的路由灵活且直观。让我们看一看。
¥Routing of Hono is flexible and intuitive. Let's take a look.
基本
¥Basic
ts
// HTTP Methods
app.get('/', (c) => c.text('GET /'))
app.post('/', (c) => c.text('POST /'))
app.put('/', (c) => c.text('PUT /'))
app.delete('/', (c) => c.text('DELETE /'))
// Wildcard
app.get('/wild/*/card', (c) => {
return c.text('GET /wild/*/card')
})
// Any HTTP methods
app.all('/hello', (c) => c.text('Any Method /hello'))
// Custom HTTP method
app.on('PURGE', '/cache', (c) => c.text('PURGE Method /cache'))
// Multiple Method
app.on(['PUT', 'DELETE'], '/post', (c) =>
c.text('PUT or DELETE /post')
)
// Multiple Paths
app.on('GET', ['/hello', '/ja/hello', '/en/hello'], (c) =>
c.text('Hello')
)
路径参数
¥Path Parameter
ts
app.get('/user/:name', async (c) => {
const name = c.req.param('name')
// ...
})
或一次所有参数:
¥or all parameters at once:
ts
app.get('/posts/:id/comment/:comment_id', async (c) => {
const { id, comment_id } = c.req.param()
// ...
})
可选参数
¥Optional Parameter
ts
// Will match `/api/animal` and `/api/animal/:type`
app.get('/api/animal/:type?', (c) => c.text('Animal!'))
正则表达式
¥Regexp
ts
app.get('/post/:date{[0-9]+}/:title{[a-z]+}', async (c) => {
const { date, title } = c.req.param()
// ...
})
包括斜线
¥Including slashes
ts
app.get('/posts/:filename{.+\\.png}', async (c) => {
//...
})
链式路由
¥Chained route
ts
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 实例对路由进行分组,并使用路由方法将它们添加到主应用。
¥You can group the routes with the Hono instance and add them to the main app with the route method.
ts
const book = new Hono()
book.get('/', (c) => c.text('List Books')) // GET /book
book.get('/:id', (c) => {
// GET /book/:id
const id = c.req.param('id')
return c.text('Get Book: ' + id)
})
book.post('/', (c) => c.text('Create Book')) // POST /book
const app = new Hono()
app.route('/book', book)
不改变基础的分组
¥Grouping without changing base
你还可以在保留基础的同时对多个实例进行分组。
¥You can also group multiple instances while keeping base.
ts
const book = new Hono()
book.get('/book', (c) => c.text('List Books')) // GET /book
book.post('/book', (c) => c.text('Create Book')) // POST /book
const user = new Hono().basePath('/user')
user.get('/', (c) => c.text('List Users')) // GET /user
user.post('/', (c) => c.text('Create User')) // POST /user
const app = new Hono()
app.route('/', book) // Handle /book
app.route('/', user) // Handle /user
基本路径
¥Base path
你可以指定基本路径。
¥You can specify the base path.
ts
const api = new Hono().basePath('/api')
api.get('/book', (c) => c.text('List Books')) // GET /api/book
使用主机名进行路由
¥Routing with hostname
如果它包含主机名,它可以正常工作。
¥It works fine if it includes a hostname.
ts
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
标头值
¥Routing with host
Header value
如果在 Hono 构造函数中设置 getPath()
函数,Hono 可以处理 host
标头值。
¥Hono can handle the host
header value if you set the getPath()
function in the Hono constructor.
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('hello www1'))
// A following request will match the route:
// new Request('http://www1.example.com/hello', {
// headers: { host: 'www1.example.com' },
// })
例如,通过应用此功能,你可以通过 User-Agent
标头更改路由。
¥By applying this, for example, you can change the routing by User-Agent
header.
路由优先级
¥Routing priority
处理程序或中间件将按注册顺序执行。
¥Handlers or middleware will be executed in registration order.
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`
执行处理程序时,该过程将停止。
¥When a handler is executed, the process will be stopped.
ts
app.get('*', (c) => c.text('common')) // common
app.get('/foo', (c) => c.text('foo')) // foo
GET /foo ---> `common` // foo will not be dispatched
如果你有要执行的中间件,请在处理程序上方编写代码。
¥If you have the middleware that you want to execute, write the code above the handler.
ts
app.use(logger())
app.get('/foo', (c) => c.text('foo'))
如果你想要有一个 "fallback" 处理程序,请在另一个处理程序下方编写代码。
¥If you want to have a "fallback" handler, write the code below the other handler.
ts
app.get('/bar', (c) => c.text('bar')) // bar
app.get('*', (c) => c.text('fallback')) // fallback
GET /bar ---> `bar`
GET /foo ---> `fallback`
分组顺序
¥Grouping ordering
请注意,分组路由的错误很难注意到。route()
函数从第二个参数(例如 three
或 two
)获取存储的路由并将其添加到其自己的(two
或 app
)路由中。
¥Note that the mistake of grouping routings is hard to notice. The route()
function takes the stored routing from the second argument (such as three
or two
) and adds it to its own (two
or app
) routing.
ts
three.get('/hi', (c) => c.text('hi'))
two.route('/three', three)
app.route('/two', two)
export default app
它将返回 200 个响应。
¥It will return 200 response.
GET /two/three/hi ---> `hi`
但是,如果它们的顺序错误,它将返回 404。
¥However, if they are in the wrong order, it will return a 404.
ts
three.get('/hi', (c) => c.text('hi'))
app.route('/two', two) // `two` does not have routes
two.route('/three', three)
export default app
GET /two/three/hi ---> 404 Not Found