Context(上下文)
Context 对象会为每个请求创建,并在返回响应前一直存在。你可以向其中存放数据、设置响应头与状态码,并访问 HonoRequest 和 Response 对象。
req
req 是 HonoRequest 的实例。详情见 HonoRequest。
app.get('/hello', (c) => {
const userAgent = c.req.header('User-Agent')
// ...
})status()
可以通过 c.status() 设置 HTTP 状态码,默认值为 200。当状态码就是 200 时无需显式调用。
app.post('/posts', (c) => {
// 设置 HTTP 状态码
c.status(201)
return c.text('你的文章已经创建!')
})header()
可以为响应设置 HTTP 头。
app.get('/', (c) => {
// 设置响应头
c.header('X-Message', '我的自定义消息')
return c.text('你好!')
})body()
返回一个 HTTP 响应。
INFO
注意:当返回文本或 HTML 时,推荐使用 c.text() 或 c.html()。
app.get('/welcome', (c) => {
c.header('Content-Type', 'text/plain')
// 返回响应主体
return c.body('感谢你的到访')
})也可以这样写:
app.get('/welcome', (c) => {
return c.body('感谢你的到访', 201, {
'X-Message': '你好!',
'Content-Type': 'text/plain',
})
})返回结果与下面的 Response 对象相同。
new Response('感谢你的到访', {
status: 201,
headers: {
'X-Message': '你好!',
'Content-Type': 'text/plain',
},
})text()
以 Content-Type:text/plain 渲染文本。
app.get('/say', (c) => {
return c.text('你好!')
})json()
以 Content-Type:application/json 渲染 JSON。
app.get('/api', (c) => {
return c.json({ message: '你好!' })
})html()
以 Content-Type:text/html 渲染 HTML。
app.get('/', (c) => {
return c.html('<h1>你好!Hono!</h1>')
})notFound()
返回一个 Not Found 响应。也可以使用 app.notFound() 自定义内容。
app.get('/notfound', (c) => {
return c.notFound()
})redirect()
执行重定向,默认状态码为 302。
app.get('/redirect', (c) => {
return c.redirect('/')
})
app.get('/redirect-permanently', (c) => {
return c.redirect('/', 301)
})res
可以访问待返回的 Response 对象。
// Response 对象
app.use('/', async (c, next) => {
await next()
c.res.headers.append('X-Debug', '调试信息')
})set() / get()
可以在一次请求生命周期内读写任意键值对,从而在中间件之间或中间件与路由处理函数之间传递数据。
app.use(async (c, next) => {
c.set('message', 'Hono 超赞!!')
await next()
})
app.get('/', (c) => {
const message = c.get('message')
return c.text(`消息内容是「${message}」`)
})将 Variables 作为泛型参数传给 Hono 构造函数,就能获得类型安全。
type Variables = {
message: string
}
const app = new Hono<{ Variables: Variables }>()c.set / c.get 的值只在同一个请求中有效,不能在不同请求之间共享或持久化。
var
还可以通过 c.var 访问变量的值。
const result = c.var.client.oneMethod()如果想编写提供自定义方法的中间件,可以这样写:
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('你好!'))
})若希望在多个处理函数中复用该中间件,可以结合 app.use()。这时需要将 Env 作为泛型传入 Hono 构造函数以确保类型安全。
const app = new Hono<Env>()
app.use(echoMiddleware)
app.get('/echo', (c) => {
return c.text(c.var.echo('你好!'))
})render() / setRenderer()
可以在自定义中间件内调用 c.setRenderer() 设置布局。
app.use(async (c, next) => {
c.setRenderer((content) => {
return c.html(
<html>
<body>
<p>{content}</p>
</body>
</html>
)
})
await next()
})随后就能通过 c.render() 在该布局内生成响应。
app.get('/', (c) => {
return c.render('你好!')
})输出结果如下:
<html>
<body>
<p>你好!</p>
</body>
</html>此外,该特性还允许自定义渲染参数。为保持类型安全,可以这样定义类型:
declare module 'hono' {
interface ContextRenderer {
(
content: string | Promise<string>,
head: { title: string }
): Response | Promise<Response>
}
}下面演示了具体用法:
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>拉面和寿司</p>, {
title: '我的最爱',
})
})
app.get('/pages/my-hobbies', (c) => {
return c.render(<p>看棒球</p>, {
title: '我的爱好',
})
})executionCtx
可以访问 Cloudflare Workers 特有的 ExecutionContext。
// ExecutionContext 对象
app.get('/foo', async (c) => {
c.executionCtx.waitUntil(c.env.KV.put(key, data))
// ...
})event
还可以访问 Cloudflare Workers 特有的 FetchEvent。这曾用于“Service Worker”语法,但现在已经不再推荐。
// 类型定义以辅助类型推断
type Bindings = {
MY_KV: KVNamespace
}
const app = new Hono<{ Bindings: Bindings }>()
// FetchEvent 对象(仅在使用 Service Worker 语法时可用)
app.get('/foo', async (c) => {
c.event.waitUntil(c.env.MY_KV.put(key, data))
// ...
})env
在 Cloudflare Workers 中,绑定到 Worker 的环境变量、密钥、KV 命名空间、D1 数据库、R2 存储桶等统称为 Binding。 无论类型如何,这些 Binding 都可以作为全局变量使用,并通过 c.env.BINDING_KEY 访问。
// 类型定义以辅助类型推断
type Bindings = {
MY_KV: KVNamespace
}
const app = new Hono<{ Bindings: Bindings }>()
// Cloudflare Workers 的环境对象
app.get('/', async (c) => {
c.env.MY_KV.get('my-key')
// ...
})error
当处理函数抛出异常时,错误对象会存放在 c.error,你可以在中间件中访问它。
app.use(async (c, next) => {
await next()
if (c.error) {
// 执行自定义逻辑...
}
})ContextVariableMap
例如,如果希望在特定中间件生效时为变量补充类型定义,可以扩展 ContextVariableMap:
declare module 'hono' {
interface ContextVariableMap {
result: string
}
}然后即可在中间件中使用:
const mw = createMiddleware(async (c, next) => {
c.set('result', '一些值') // result 是字符串
await next()
})在处理函数中,该变量会被推断为正确的类型:
app.get('/', (c) => {
const val = c.get('result') // val 是字符串
// ...
return c.json({ result: val })
})