本页还没有译文
本页 33 段还没译成简体中文,下面显示的是英文原文。Middleware
还没翻译译自英文(hono.dev)本页 33 段都还没译
模型写的
背景方法设置结果分析局限
Middleware
中间件在分发前后包裹端点处理器
Middleware works before/after the endpoint Handler. We can get the Request before dispatching or manipulate the Response after dispatching.Middleware works before/after the endpoint Handler. We can get the Request before dispatching or manipulate the Response after dispatching.中间件在端点 Handler 前后工作 它可在分发前获取 Request,分发后操作 Response中间件在端点 Handler 前后工作端点 Handler
Definition of Middleware
处理器返回 Response;中间件 await next 或提前退出
- Handler - should return
Responseobject. Only one handler will be called.Handler - should return Response object. Only one handler will be called.Handler 返回 Response 且只调用一个Handler 返回 Response 且只调用一个Handler - Middleware - should
await next()and return nothing to call the next Middleware, or return aResponseto early-exit.Middleware - should await next() and return nothing to call the next Middleware, or return a Response to early-exit.中间件 await next 返回空,或返回 Response await next 调用下一个中间件;返回 Response 则提前退出中间件 await next 返回空,或返回 Response中间件
The user can register middleware using app.use or using app.HTTP_METHOD as well as the handlers. For this feature, it's easy to specify the path and the method.The user can register middleware using app.use or using app.HTTP_METHOD as well as the handlers. For this feature, it's easy to specify the path and the method.用 app.use 或 app.HTTP_METHOD 注册中间件 两者都能方便地指定路径和方法用 app.use 或 app.HTTP_METHOD 注册中间件app.use
// match any method, all routes
app.use(logger())
// specify path
app.use('/posts/*', cors())
// specify method and path
app.post('/posts/*', basicAuth())If the handler returns Response, it will be used for the end-user and will stop processing.If the handler returns Response, it will be used for the end-user and will stop processing.处理器返回 Response 会停止处理并送给最终用户处理器返回 Response 会停止处理并送给最终用户最终用户 Response
app.post('/posts', (c) => c.text('Created!', 201))In this case, four middleware are processed before dispatching like this:In this case, four middleware are processed before dispatching like this:处理器分发前处理四个中间件处理器分发前处理四个中间件中间件处理
logger() -> cors() -> basicAuth() -> *handler*Execution order
执行顺序依注册顺序,围绕 next 嵌套
The order in which Middleware is executed is determined by the order in which it is registered.
The process before the next of the first registered Middleware is executed first,
and the process after the next is executed last.
See below.The order in which Middleware is executed is determined by the order in which it is registered. The process before the next of the first registered Middleware is executed first,
and the process after the next is executed last.中间件按注册顺序围绕 next 执行 首个注册中间件的 next 前代码最先执行,next 后代码最后执行中间件按注册顺序围绕 next 执行注册顺序
app.use(async (_, next) => {
console.log('middleware 1 start')
await next()
console.log('middleware 1 end')
})
app.use(async (_, next) => {
console.log('middleware 2 start')
await next()
console.log('middleware 2 end')
})
app.use(async (_, next) => {
console.log('middleware 3 start')
await next()
console.log('middleware 3 end')
})
app.get('/', (c) => {
console.log('handler')
return c.text('Hello!')
})Result is the following.Result is the following.日志显示 1、2、3 依次开始,handler 后逆序结束日志显示 1、2、3 依次开始,handler 后逆序结束日志嵌套
middleware 1 start
middleware 2 start
middleware 3 start
handler
middleware 3 end
middleware 2 end
middleware 1 end
Note that if the handler or any middleware throws, hono will catch it and either pass it to your app.onError() callback or automatically convert it to a 500 response before returning it up the chain of middleware. This means that next() will never throw, so there is no need to wrap it in a try/catch/finally.Note that if the handler or any middleware throws, hono will catch it and either pass it to your app.onError() callback or automatically convert it to a 500 response before returning it up the chain of middleware. This means that next() will never throw, so there is no need to wrap it in a try/catch/finally.next() 不会抛错,无需 try/catch Hono 捕获抛出的错误,交给 app.onError 或转换为 500next() 不会抛错,无需 try/catchnext()
Built-in Middleware
Hono 内置 poweredBy、logger、basicAuth 等中间件
Hono has built-in middleware.Hono has built-in middleware.Hono 内置 poweredBy、logger、basicAuth 等中间件Hono 内置 poweredBy、logger、basicAuth 等中间件内置中间件
import { Hono } from 'hono'
import { poweredBy } from 'hono/powered-by'
import { logger } from 'hono/logger'
import { basicAuth } from 'hono/basic-auth'
const app = new Hono()
app.use(poweredBy())
app.use(logger())
app.use(
'/auth/*',
basicAuth({
username: 'hono',
password: 'acoolproject',
})
)Warning
In Deno, it is possible to use a different version of middleware than the Hono version, but this can lead to bugs. For example, this code is not working because the version is different.In Deno, it is possible to use a different version of middleware than the Hono version, but this can lead to bugs. For example, this code is not working because the version is different.Deno 中间件版本不一致会导致 bug 中间件版本与 Hono 版本不同可能使 upgradeWebSocket 等代码失效Deno 中间件版本不一致会导致 bugDeno 版本
import { Hono } from 'jsr:@hono/hono@4.4.0'
import { upgradeWebSocket } from 'jsr:@hono/hono@4.4.5/deno'
const app = new Hono()
app.get(
'/ws',
upgradeWebSocket(() => ({
// ...
}))
)Custom Middleware
可在 app.use 内联写中间件,或用 createMiddleware 分离
You can write your own middleware directly inside app.use():You can write your own middleware directly inside app.use():可直接在 app.use() 内编写自定义中间件可直接在 app.use() 内编写自定义中间件自定义中间件
// Custom logger
app.use(async (c, next) => {
console.log(`[${c.req.method}] ${c.req.url}`)
await next()
})
// Add a custom header
app.use('/message/*', async (c, next) => {
await next()
c.header('x-message', 'This is middleware!')
})
app.get('/message/hello', (c) => c.text('Hello Middleware!'))However, embedding middleware directly within app.use() can limit its reusability. Therefore, we can separate our middleware into different files.However, embedding middleware directly within app.use() can limit its reusability. Therefore, we can separate our middleware into different files.内联中间件复用性差,应分离到不同文件 将中间件拆到各自文件后可在应用中复用内联中间件复用性差,应分离到不同文件内联中间件
To ensure we don't lose type definitions for context and next, when separating middleware, we can use createMiddleware() from Hono's factory. This also allows us to type-safely access data we've set in Context from downstream handlers.To ensure we don't lose type definitions for context and next, when separating middleware, we can use createMiddleware() from Hono's factory. This also allows us to type-safely access data we've set in Context from downstream handlers.分离时用 createMiddleware() 保留 context 和 next 类型 它还让下游处理器类型安全地访问 Context 中 set 的数据分离时用 createMiddleware() 保留 context 和 next 类型createMiddleware()
import { createMiddleware } from 'hono/factory'
const logger = createMiddleware(async (c, next) => {
console.log(`[${c.req.method}] ${c.req.url}`)
await next()
})Note
Type generics can be used with createMiddleware:Type generics can be used with createMiddleware:createMiddleware 可接受 Bindings 等类型泛型createMiddleware 可接受 Bindings 等类型泛型createMiddleware
createMiddleware<{Bindings: Bindings}>(async (c, next) =>Modify the Response After Next
中间件可在 await next 后替换响应
Additionally, middleware can be designed to modify responses if necessary:Additionally, middleware can be designed to modify responses if necessary:中间件可在 next 后替换 c.res 修改响应中间件可在 next 后替换 c.res 修改响应c.res
const stripRes = createMiddleware(async (c, next) => {
await next()
c.res = undefined
c.res = new Response('New Response')
})Context access inside Middleware arguments
在中间件参数内使用 context 参数
To access the context inside middleware arguments, directly use the context parameter provided by app.use. See the example below for clarification.To access the context inside middleware arguments, directly use the context parameter provided by app.use. See the example below for clarification.在中间件参数内直接使用 context 参数 配置中间件时传入相同的 c 与 next 即可访问 context在中间件参数内直接使用 context 参数context 参数
import { cors } from 'hono/cors'
app.use('*', async (c, next) => {
const middleware = cors({
origin: c.env.CORS_ORIGIN,
})
return middleware(c, next)
})Extending the Context in Middleware
用 c.set 和 Variables 泛型类型安全地扩展 context
To extend the context inside middleware, use c.set. You can make this type-safe by passing a { Variables: { yourVariable: YourVariableType } } generic argument to the createMiddleware function.To extend the context inside middleware, use c.set. You can make this type-safe by passing a { Variables: { yourVariable: YourVariableType } } generic argument to the createMiddleware function.用 c.set 和 Variables 泛型类型安全地扩展 context 向 createMiddleware 传 Variables 使下游处理器类型安全地使用该值用 c.set 和 Variables 泛型类型安全地扩展 contextc.set
import { createMiddleware } from 'hono/factory'
const echoMiddleware = createMiddleware<{
Variables: {
echo: (str: string) => string
}
}>(async (c, next) => {
c.set('echo', (str) => str)
await next()
})
app.get('/echo', echoMiddleware, (c) => {
return c.text(c.var.echo('Hello!'))
})Type Inference Across Chained Middleware
链式 .use() 调用自动累积 Variables 类型
When you chain multiple middleware using .use(), Hono automatically accumulates the Variables types. Route handlers that follow the middleware chain can access all variables from every preceding middleware in a type-safe way:When you chain multiple middleware using .use(), Hono automatically accumulates the Variables types. Route handlers that follow the middleware chain can access all variables from every preceding middleware in a type-safe way:链式 .use() 调用自动累积 Variables 类型 链后的路由处理器可类型安全地访问所有前置变量链式 .use() 调用自动累积 Variables 类型Variables 类型
import { createMiddleware } from 'hono/factory'
const authMiddleware = createMiddleware<{
Variables: { user: { id: string; name: string } }
}>(async (c, next) => {
c.set('user', { id: '123', name: 'Alice' })
await next()
})
const dbMiddleware = createMiddleware<{
Variables: { db: { query: (sql: string) => Promise<unknown> } }
}>(async (c, next) => {
c.set('db', {
query: async (sql) => {
/* ... */
},
})
await next()
})
const app = new Hono()
.use(authMiddleware)
.use(dbMiddleware)
.get('/', (c) => {
// Both `user` and `db` are available and type-safe
const user = c.var.user // { id: string; name: string }
const db = c.var.db // { query: (sql: string) => Promise<unknown> }
return c.json({ user })
})This works because each .use() call returns a new Hono instance with the merged type, so the type grows as middleware is chained. This eliminates the need to manually declare a combined Env type upfront for most use cases.This works because each .use() call returns a new Hono instance with the merged type, so the type grows as middleware is chained. This eliminates the need to manually declare a combined Env type upfront for most use cases..use() 返回带合并类型的新 Hono 实例 类型随中间件链增长,无需手动声明合并的 Env 类型.use() 返回带合并类型的新 Hono 实例Hono 实例
Third-party Middleware
第三方中间件依赖库,用于更复杂的应用
Built-in middleware does not depend on external modules, but third-party middleware can depend on third-party libraries. So with them, we may make a more complex application.Built-in middleware does not depend on external modules, but third-party middleware can depend on third-party libraries. So with them, we may make a more complex application.第三方中间件依赖外部库,用于更复杂的应用第三方中间件依赖外部库,用于更复杂的应用第三方中间件
We can explore a variety of third-party middleware. For example, we have GraphQL Server Middleware, Sentry Middleware, Firebase Auth Middleware, and others.We can explore a variety of third-party middleware. For example, we have GraphQL Server Middleware, Sentry Middleware, Firebase Auth Middleware, and others.第三方中间件包括 GraphQL、Sentry 和 Firebase Auth第三方中间件包括 GraphQL、Sentry 和 Firebase Auth第三方中间件