Appearance
上下文
🌐 Context
Context 对象为每个请求实例化,并一直保留到响应返回。你可以在其中放入值,设置要返回的头信息和状态码,并访问 HonoRequest 和 Response 对象。
🌐 The Context object is instantiated for each request and kept until the response is returned. You can put values in it, set headers and a status code you want to return, and access HonoRequest and Response objects.
req
req 是 HonoRequest 的一个实例。更多详情,请参见 HonoRequest。
ts
app.get('/hello', (c) => {
const userAgent = c.req.header('User-Agent')
// ...
})status()
你可以使用 c.status() 设置 HTTP 状态码。默认值是 200。如果代码是 200,你不必使用 c.status()。
🌐 You can set an HTTP status code with c.status(). The default is 200. You don't have to use c.status() if the code is 200.
ts
app.post('/posts', (c) => {
// Set HTTP status code
c.status(201)
return c.text('Your post is created!')
})header()
你可以为响应设置 HTTP 标头。
🌐 You can set HTTP Headers for the response.
ts
app.get('/', (c) => {
// Set headers
c.header('X-Message', 'My custom message')
return c.text('Hello!')
})body()
返回 HTTP 响应。
🌐 Return an HTTP response.
INFO
注意:在返回文本或 HTML 时,建议使用 c.text() 或 c.html()。
ts
app.get('/welcome', (c) => {
c.header('Content-Type', 'text/plain')
// Return the response body
return c.body('Thank you for coming')
})你还可以编写以下内容。
🌐 You can also write the following.
ts
app.get('/welcome', (c) => {
return c.body('Thank you for coming', 201, {
'X-Message': 'Hello!',
'Content-Type': 'text/plain',
})
})响应与下面的 Response 对象相同。
🌐 The response is the same Response object as below.
ts
new Response('Thank you for coming', {
status: 201,
headers: {
'X-Message': 'Hello!',
'Content-Type': 'text/plain',
},
})text()
将文本呈现为 Content-Type: text/plain。
🌐 Render text as Content-Type: text/plain.
ts
app.get('/say', (c) => {
return c.text('Hello!')
})json()
将 JSON 渲染为 Content-Type: application/json。
🌐 Render JSON as Content-Type: application/json.
ts
app.get('/api', (c) => {
return c.json({ message: 'Hello!' })
})html()
将 HTML 渲染为 Content-Type: text/html。
🌐 Render HTML as Content-Type: text/html.
ts
app.get('/', (c) => {
return c.html('<h1>Hello! Hono!</h1>')
})notFound()
返回一个 Not Found 响应。你可以使用 app.notFound() 对其进行自定义。
🌐 Return a Not Found Response. You can customize it with app.notFound().
ts
app.get('/notfound', (c) => {
return c.notFound()
})redirect()
重定向,默认状态码是 302。
🌐 Redirect, default status code is 302.
ts
app.get('/redirect', (c) => {
return c.redirect('/')
})
app.get('/redirect-permanently', (c) => {
return c.redirect('/', 301)
})res
你可以访问将被返回的 Response 对象。
🌐 You can access the Response object that will be returned.
ts
// Response object
app.use('/', async (c, next) => {
await next()
c.res.headers.append('X-Debug', 'Debug message')
})set() / get()
获取和设置任意键值对,其生命周期为当前请求。这允许在中间件之间或从中间件到路由处理程序传递特定值。
🌐 Get and set arbitrary key-value pairs, with a lifetime of the current request. This allows passing specific values between middleware or from middleware to route handlers.
ts
app.use(async (c, next) => {
c.set('message', 'Hono is cool!!')
await next()
})
app.get('/', (c) => {
const message = c.get('message')
return c.text(`The message is "${message}"`)
})将 Variables 作为泛型传递给 Hono 的构造函数以使其类型安全。
🌐 Pass the Variables as Generics to the constructor of Hono to make it type-safe.
ts
type Variables = {
message: string
}
const app = new Hono<{ Variables: Variables }>()c.set / c.get 的值仅在同一请求内保留。它们不能在不同请求之间共享或持久化。
🌐 The value of c.set / c.get are retained only within the same request. They cannot be shared or persisted across different requests.
var
你也可以使用 c.var 访问变量的值。
🌐 You can also access the value of a variable with c.var.
ts
const result = c.var.client.oneMethod()如果你想创建提供自定义方法的中间件,请像下面这样编写:
🌐 If you want to create the middleware which provides a custom method, write like the following:
ts
type Env = {
Variables: {
echo: (str: string) => string
}
}
const app = new Hono()
const echoMiddleware = createMiddleware<Env>(async (c, next) => {
c.set('echo', (str) => str)
await next()
})
app.get('/echo', echoMiddleware, (c) => {
return c.text(c.var.echo('Hello!'))
})如果你想在多个处理程序中使用中间件,你可以使用 app.use()。然后,你必须将 Env 作为泛型传递给 Hono 的构造函数以确保类型安全。
🌐 If you want to use the middleware in multiple handlers, you can use app.use(). Then, you have to pass the Env as Generics to the constructor of Hono to make it type-safe.
ts
const app = new Hono<Env>()
app.use(echoMiddleware)
app.get('/echo', (c) => {
return c.text(c.var.echo('Hello!'))
})render() / setRenderer()
你可以在自定义中间件中使用 c.setRenderer() 设置布局。
🌐 You can set a layout using c.setRenderer() within a custom middleware.
tsx
app.use(async (c, next) => {
c.setRenderer((content) => {
return c.html(
<html>
<body>
<p>{content}</p>
</body>
</html>
)
})
await next()
})然后,你可以使用 c.render() 在此布局中创建响应。
🌐 Then, you can utilize c.render() to create responses within this layout.
ts
app.get('/', (c) => {
return c.render('Hello!')
})其输出将是:
🌐 The output of which will be:
html
<html>
<body>
<p>Hello!</p>
</body>
</html>此外,此功能提供了自定义参数的灵活性。为了确保类型安全,可以将类型定义为:
🌐 Additionally, this feature offers the flexibility to customize arguments. To ensure type safety, types can be defined as:
ts
declare module 'hono' {
interface ContextRenderer {
(
content: string | Promise<string>,
head: { title: string }
): Response | Promise<Response>
}
}以下是如何使用它的示例:
🌐 Here's an example of how you can use this:
ts
app.use('/pages/*', async (c, next) => {
c.setRenderer((content, head) => {
return c.html(
<html>
<head>
<title>{head.title}</title>
</head>
<body>
<header>{head.title}</header>
<p>{content}</p>
</body>
</html>
)
})
await next()
})
app.get('/pages/my-favorite', (c) => {
return c.render(<p>Ramen and Sushi</p>, {
title: 'My favorite',
})
})
app.get('/pages/my-hobbies', (c) => {
return c.render(<p>Watching baseball</p>, {
title: 'My hobbies',
})
})executionCtx
你可以访问 Cloudflare Workers 的特定 ExecutionContext。
🌐 You can access Cloudflare Workers' specific ExecutionContext.
ts
// ExecutionContext object
app.get('/foo', async (c) => {
c.executionCtx.waitUntil(c.env.KV.put(key, data))
// ...
})ExecutionContext 也有一个 exports 字段。要使用 Wrangler 生成的类型获得自动补齐,你可以使用模块扩展:
🌐 The ExecutionContext also has an exports field. To get autocomplete with Wrangler's generated types, you can use module augmentation:
ts
import 'hono'
declare module 'hono' {
interface ExecutionContext {
readonly exports: Cloudflare.Exports
}
}event
你可以访问 Cloudflare Workers 的特定 FetchEvent。这曾在“Service Worker”语法中使用过。但现在不推荐使用。
🌐 You can access Cloudflare Workers' specific FetchEvent. This was used in "Service Worker" syntax. But, it is not recommended now.
ts
// Type definition to make type inference
type Bindings = {
MY_KV: KVNamespace
}
const app = new Hono<{ Bindings: Bindings }>()
// FetchEvent object (only set when using Service Worker syntax)
app.get('/foo', async (c) => {
c.event.waitUntil(c.env.MY_KV.put(key, data))
// ...
})env
在 Cloudflare Workers 中,绑定到 Worker 的环境变量、密钥、KV 命名空间、D1 数据库、R2 存储桶等称为绑定。无论类型如何,绑定始终作为全局变量可用,并且可以通过上下文 c.env.BINDING_KEY 访问。
🌐 In Cloudflare Workers Environment variables, secrets, KV namespaces, D1 database, R2 bucket etc. that are bound to a worker are known as bindings. Regardless of type, bindings are always available as global variables and can be accessed via the context c.env.BINDING_KEY.
ts
// Type definition to make type inference
type Bindings = {
MY_KV: KVNamespace
}
const app = new Hono<{ Bindings: Bindings }>()
// Environment object for Cloudflare Workers
app.get('/', async (c) => {
c.env.MY_KV.get('my-key')
// ...
})error
如果处理器抛出错误,错误对象将被放置在 c.error 中。你可以在中间件中访问它。
🌐 If the Handler throws an error, the error object is placed in c.error. You can access it in your middleware.
ts
app.use(async (c, next) => {
await next()
if (c.error) {
// do something...
}
})ContextVariableMap
WARNING
ContextVariableMap 全局地向所有上下文添加类型,无论设置该变量的中间件是否实际运行。这意味着即使在从未注册你的中间件的处理器中,c.get('result') 也会显得类型安全,从而可能在运行时隐藏 undefined 错误。
看看下面的例子:
🌐 Take a look at the following example:
ts
declare module 'hono' {
interface ContextVariableMap {
result: string
}
}
const mw = createMiddleware(async (c, next) => {
c.set('result', 'some values')
await next()
})
const app = new Hono()
// handler uses the middleware
app.get('/foo', mw, (c) => {
const val = c.get('result') // ✅ val is a string and typed as such, as expected
})
// handler doesn't use the middleware
app.get('/bar', (c) => {
const val = c.get('result') // ❌ val is undefined but typed as a string, which can lead to runtime errors
})你可以扩展 ContextVariableMap 接口,以在整个应用中全局定义上下文变量的类型。当一个变量由应用于整个应用的中间件设置并且在上下文中保证存在时,这种做法是合适的。
🌐 You can augment the ContextVariableMap interface to define types for context variables globally across your entire application. This is appropriate when a variable is set by middleware that is applied app-wide and is guaranteed to exist in the context.
例如:
🌐 For example:
ts
declare module 'hono' {
interface ContextVariableMap {
result: string
}
}然后,你可以在中间件中使用它:
🌐 You can then utilize this in your middleware:
ts
const mw = createMiddleware(async (c, next) => {
c.set('result', 'some values') // result is a string
await next()
})在处理程序中,变量被推断为正确的类型:
🌐 In a handler, the variable is inferred as the proper type:
ts
app.get('/', (c) => {
const val = c.get('result') // val is a string
// ...
return c.json({ result: val })
})