跳转到正文

上下文 ​

每个请求都会创建一个 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,就不必调用 c.status()。

ts
app
.
post
('/posts', (
c
) => {
// Set HTTP status code
c
.
status
(201)
return
c
.
text
('Your post is created!')
})

可以为响应设置 HTTP 响应头。

ts
app
.
get
('/', (
c
) => {
// Set headers
c
.
header
('X-Message', 'My custom message')
return
c
.
text
('Hello!')
})

body() ​

返回 HTTP 响应。

说明

注意:返回文本或 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')
})

也可以采用以下写法。

ts
app
.
get
('/welcome', (
c
) => {
return
c
.
body
('Thank you for coming', 201, {
'X-Message': 'Hello!', 'Content-Type': 'text/plain', }) })

响应与下面的 Response 对象相同。

ts
new 
Response
('Thank you for coming', {
status
: 201,
headers
: {
'X-Message': 'Hello!', 'Content-Type': 'text/plain', }, })

text() ​

以 Content-Type: text/plain 返回文本。

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

json() ​

以 Content-Type: application/json 返回 JSON。

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

html() ​

以 Content-Type: text/html 返回 HTML。

ts
app
.
get
('/', (
c
) => {
return
c
.
html
('<h1>Hello! 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 object
app
.
use
('/', async (
c
,
next
) => {
await
next
()
c
.
res
.
headers
.
append
('X-Debug', 'Debug message')
})

set() / get() ​

获取和设置任意键值对,其生命周期为当前请求。这样可以在中间件之间,或从中间件向路由处理程序传递特定值。

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 的构造函数,就可以确保类型安全。

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

如果想在多个处理程序中使用该中间件,可以调用 app.use()。 此时,需要将 Env 作为泛型传入 Hono 的构造函数,以确保类型安全。

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

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

输出结果如下:

html
<html>
  <body>
    <p>Hello!</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>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。

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

ExecutionContext 还有一个 exports 字段。要配合 Wrangler 生成的类型获得自动补全,可以使用模块扩展:

ts
import 'hono'

declare module 'hono' {
  interface ExecutionContext {
    readonly exports: Cloudflare.Exports
  }
}

event ​

可以访问 Cloudflare Workers 特有的 FetchEvent。它用于“Service Worker”语法,但现在已不推荐使用。

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 存储桶等统称为绑定(bindings)。 无论类型如何,绑定始终作为全局变量可用,也可以通过上下文中的 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 中。 可以在中间件中访问它。

ts
app
.
use
(async (
c
,
next
) => {
await
next
()
if (
c
.
error
) {
// do something... } })

ContextVariableMap ​

注意

ContextVariableMap 会向所有上下文全局添加类型,无论设置该变量的中间件是否实际执行过。这意味着,即使某个处理程序从未注册你的中间件,c.get('result') 也会看起来是类型安全的,从而可能掩盖运行时的 undefined 错误。

请看以下示例:

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 接口,为整个应用中的上下文变量全局定义类型。这适用于由应用全局中间件设置,且能保证在上下文中存在的变量。

例如:

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

然后可以在中间件中使用它:

ts
const 
mw
=
createMiddleware
(async (
c
,
next
) => {
c
.
set
('result', 'some values') // result is a string
await
next
()
})

在处理程序中,变量会被推断为正确的类型:

ts
app
.
get
('/', (
c
) => {
const
val
=
c
.
get
('result') // val is a string
// ... return
c
.
json
({
result
:
val
})
})

基于 MIT 许可证发布。