Skip to content

Context(上下文)

Context 对象会为每个请求创建,并在返回响应前一直存在。你可以向其中存放数据、设置响应头与状态码,并访问 HonoRequest 和 Response 对象。

req

req 是 HonoRequest 的实例。详情见 HonoRequest

ts
app
.
get
('/hello', (
c
) => {
const
userAgent
=
c
.
req
.
header
('User-Agent')
// ... })

status()

可以通过 c.status() 设置 HTTP 状态码,默认值为 200。当状态码就是 200 时无需显式调用。

ts
app
.
post
('/posts', (
c
) => {
// 设置 HTTP 状态码
c
.
status
(201)
return
c
.
text
('你的文章已经创建!')
})

可以为响应设置 HTTP 头。

ts
app
.
get
('/', (
c
) => {
// 设置响应头
c
.
header
('X-Message', '我的自定义消息')
return
c
.
text
('你好!')
})

body()

返回一个 HTTP 响应。

INFO

注意:当返回文本或 HTML 时,推荐使用 c.text()c.html()

ts
app
.
get
('/welcome', (
c
) => {
c
.
header
('Content-Type', 'text/plain')
// 返回响应主体 return
c
.
body
('感谢你的到访')
})

也可以这样写:

ts
app
.
get
('/welcome', (
c
) => {
return
c
.
body
('感谢你的到访', 201, {
'X-Message': '你好!', 'Content-Type': 'text/plain', }) })

返回结果与下面的 Response 对象相同。

ts
new 
Response
('感谢你的到访', {
status
: 201,
headers
: {
'X-Message': '你好!', 'Content-Type': 'text/plain', }, })

text()

Content-Type:text/plain 渲染文本。

ts
app
.
get
('/say', (
c
) => {
return
c
.
text
('你好!')
})

json()

Content-Type:application/json 渲染 JSON。

ts
app
.
get
('/api', (
c
) => {
return
c
.
json
({
message
: '你好!' })
})

html()

Content-Type:text/html 渲染 HTML。

ts
app
.
get
('/', (
c
) => {
return
c
.
html
('<h1>你好!Hono!</h1>')
})

notFound()

返回一个 Not Found 响应。也可以使用 app.notFound() 自定义内容。

ts
app
.
get
('/notfound', (
c
) => {
return
c
.
notFound
()
})

redirect()

执行重定向,默认状态码为 302

ts
app
.
get
('/redirect', (
c
) => {
return
c
.
redirect
('/')
})
app
.
get
('/redirect-permanently', (
c
) => {
return
c
.
redirect
('/', 301)
})

res

可以访问待返回的 Response 对象。

ts
// Response 对象
app
.
use
('/', async (
c
,
next
) => {
await
next
()
c
.
res
.
headers
.
append
('X-Debug', '调试信息')
})

set() / get()

可以在一次请求生命周期内读写任意键值对,从而在中间件之间或中间件与路由处理函数之间传递数据。

ts
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 构造函数,就能获得类型安全。

ts
type 
Variables
= {
message
: string
} const
app
= new
Hono
<{
Variables
:
Variables
}>()

c.set / c.get 的值只在同一个请求中有效,不能在不同请求之间共享或持久化。

var

还可以通过 c.var 访问变量的值。

ts
const 
result
=
c
.
var
.client.oneMethod()

如果想编写提供自定义方法的中间件,可以这样写:

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
('你好!'))
})

若希望在多个处理函数中复用该中间件,可以结合 app.use()。这时需要将 Env 作为泛型传入 Hono 构造函数以确保类型安全。

ts
const 
app
= new
Hono
<
Env
>()
app
.
use
(
echoMiddleware
)
app
.
get
('/echo', (
c
) => {
return
c
.
text
(
c
.
var
.
echo
('你好!'))
})

render() / setRenderer()

可以在自定义中间件内调用 c.setRenderer() 设置布局。

tsx
app
.
use
(async (
c
,
next
) => {
c
.
setRenderer
((
content
) => {
return
c
.
html
(
<
html
>
<
body
>
<
p
>{
content
}</
p
>
</
body
>
</
html
>
) }) await
next
()
})

随后就能通过 c.render() 在该布局内生成响应。

ts
app
.
get
('/', (
c
) => {
return
c
.
render
('你好!')
})

输出结果如下:

html
<html>
  <body>
    <p>你好!</p>
  </body>
</html>

此外,该特性还允许自定义渲染参数。为保持类型安全,可以这样定义类型:

ts
declare module 'hono' {
  interface ContextRenderer {
    (
      content: string | Promise<string>,
      head: { title: string }
    ): Response | Promise<Response>
  }
}

下面演示了具体用法:

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>拉面和寿司</p>, {
    title: '我的最爱',
  })
})

app.get('/pages/my-hobbies', (c) => {
  return c.render(<p>看棒球</p>, {
    title: '我的爱好',
  })
})

executionCtx

可以访问 Cloudflare Workers 特有的 ExecutionContext

ts
// ExecutionContext 对象
app
.
get
('/foo', async (
c
) => {
c
.
executionCtx
.
waitUntil
(
c
.
env
.
KV
.put(
key
,
data
))
// ... })

event

还可以访问 Cloudflare Workers 特有的 FetchEvent。这曾用于“Service Worker”语法,但现在已经不再推荐。

ts
// 类型定义以辅助类型推断
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 访问。

ts
// 类型定义以辅助类型推断
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,你可以在中间件中访问它。

ts
app
.
use
(async (
c
,
next
) => {
await
next
()
if (
c
.
error
) {
// 执行自定义逻辑... } })

ContextVariableMap

例如,如果希望在特定中间件生效时为变量补充类型定义,可以扩展 ContextVariableMap

ts
declare module 'hono' {
  interface ContextVariableMap {
    result: string
  }
}

然后即可在中间件中使用:

ts
  const 
mw
=
createMiddleware
(async (
c
,
next
) => {
c
.
set
('result', '一些值') // result 是字符串
await
next
()
})

在处理函数中,该变量会被推断为正确的类型:

ts
app
.
get
('/', (
c
) => {
const
val
=
c
.
get
('result') // val 是字符串
// ... return
c
.
json
({
result
:
val
})
})

Released under the MIT License.