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')) // commonGET /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')) // fooGET /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')) // fallbackGET /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 appGET /two/three/hi ---> 404 Not Found