hono

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Hono Skill

Hono 技能

Build Hono web applications. This skill provides inline API knowledge for AI. Use
npx hono request
to test endpoints.
构建Hono Web应用。本技能为AI提供嵌入式API知识。使用
npx hono request
测试端点。

Latest Documentation

最新文档

For details beyond this inline reference, fetch the latest documentation from https://hono.dev. Get the index of doc pages from
https://hono.dev/llms.txt
, then fetch a page with the
Accept: text/markdown
header to receive it as Markdown:
bash
curl -H "Accept: text/markdown" https://hono.dev/docs/helpers/cookie
如需了解本嵌入式参考之外的详细内容,请从https://hono.dev获取最新文档。从`https://hono.dev/llms.txt`获取文档页面索引,然后通过`Accept: text/markdown`请求头获取Markdown格式的页面:
bash
curl -H "Accept: text/markdown" https://hono.dev/docs/helpers/cookie

Hono CLI Usage

Hono CLI 使用方法

Request Testing

请求测试

Test endpoints without starting an HTTP server. Uses
app.request()
internally.
bash
undefined
无需启动HTTP服务器即可测试端点。内部使用
app.request()
bash
undefined

GET request

GET 请求

npx hono request [file] -P /path
npx hono request [file] -P /path

POST request with JSON body

带JSON请求体的POST请求

npx hono request [file] -X POST -P /api/users -d '{"name": "test"}'

**Note:** Do not pass credentials directly in CLI arguments. Use environment variables for sensitive values. `hono request` does not support Cloudflare Workers bindings (KV, D1, R2, etc.). When bindings are required, use `workers-fetch` instead:

```bash
npx workers-fetch /path
npx workers-fetch -X POST -H "Content-Type:application/json" -d '{"name":"test"}' /api/users

npx hono request [file] -X POST -P /api/users -d '{"name": "test"}'

**注意:** 不要在CLI参数中直接传递凭证。敏感值请使用环境变量。`hono request`不支持Cloudflare Workers绑定(KV、D1、R2等)。当需要绑定时,请改用`workers-fetch`:

```bash
npx workers-fetch /path
npx workers-fetch -X POST -H "Content-Type:application/json" -d '{"name":"test"}' /api/users

Hono API Reference

Hono API 参考

App Constructor

应用构造函数

ts
import { Hono } from 'hono'

const app = new Hono()

// With TypeScript generics
type Env = {
  Bindings: { DATABASE: D1Database; KV: KVNamespace }
  Variables: { user: User }
}
const app = new Hono<Env>()
ts
import { Hono } from 'hono'

const app = new Hono()

// 使用TypeScript泛型
type Env = {
  Bindings: { DATABASE: D1Database; KV: KVNamespace }
  Variables: { user: User }
}
const app = new Hono<Env>()

Routing Methods

路由方法

ts
app.get('/path', handler)
app.post('/path', handler)
app.put('/path', handler)
app.delete('/path', handler)
app.patch('/path', handler)
app.options('/path', handler)
app.all('/path', handler) // all HTTP methods
app.on('PURGE', '/path', handler) // custom method
app.on(['PUT', 'DELETE'], '/path', handler) // multiple methods
ts
app.get('/path', handler)
app.post('/path', handler)
app.put('/path', handler)
app.delete('/path', handler)
app.patch('/path', handler)
app.options('/path', handler)
app.all('/path', handler) // 所有HTTP方法
app.on('PURGE', '/path', handler) // 自定义方法
app.on(['PUT', 'DELETE'], '/path', handler) // 多个方法

Routing Patterns

路由模式

ts
// Path parameters
app.get('/user/:name', (c) => {
  const name = c.req.param('name')
  return c.json({ name })
})

// Multiple params
app.get('/posts/:id/comments/:commentId', (c) => {
  const { id, commentId } = c.req.param()
})

// Optional parameters
app.get('/api/animal/:type?', (c) => c.text('Animal!'))

// Wildcards
app.get('/wild/*/card', (c) => c.text('Wildcard'))

// Regexp constraints
app.get('/post/:date{[0-9]+}/:title{[a-z]+}', (c) => {
  const { date, title } = c.req.param()
})

// Chained routes
app
  .get('/endpoint', (c) => c.text('GET'))
  .post((c) => c.text('POST'))
  .delete((c) => c.text('DELETE'))
ts
// 路径参数
app.get('/user/:name', (c) => {
  const name = c.req.param('name')
  return c.json({ name })
})

// 多个参数
app.get('/posts/:id/comments/:commentId', (c) => {
  const { id, commentId } = c.req.param()
})

// 可选参数
app.get('/api/animal/:type?', (c) => c.text('Animal!'))

// 通配符
app.get('/wild/*/card', (c) => c.text('Wildcard'))

// 正则约束
app.get('/post/:date{[0-9]+}/:title{[a-z]+}', (c) => {
  const { date, title } = c.req.param()
})

// 链式路由
app
  .get('/endpoint', (c) => c.text('GET'))
  .post((c) => c.text('POST'))
  .delete((c) => c.text('DELETE'))

Route Grouping

路由分组

ts
// Using route()
const api = new Hono()
api.get('/users', (c) => c.json([]))

const app = new Hono()
app.route('/api', api) // mounts at /api/users

// Using basePath()
const app = new Hono().basePath('/api')
app.get('/users', (c) => c.json([])) // GET /api/users
ts
// 使用route()
const api = new Hono()
api.get('/users', (c) => c.json([]))

const app = new Hono()
app.route('/api', api) // 挂载到/api/users

// 使用basePath()
const app = new Hono().basePath('/api')
app.get('/users', (c) => c.json([])) // GET /api/users

Error Handling

错误处理

ts
app.notFound((c) => c.json({ message: 'Not Found' }, 404))

app.onError((err, c) => {
  console.error(err)
  return c.json({ message: 'Internal Server Error' }, 500)
})

ts
app.notFound((c) => c.json({ message: 'Not Found' }, 404))

app.onError((err, c) => {
  console.error(err)
  return c.json({ message: 'Internal Server Error' }, 500)
})

Context (c)

上下文 (c)

Response Methods

响应方法

ts
c.text('Hello') // text/plain
c.json({ message: 'Hello' }) // application/json
c.html('<h1>Hello</h1>') // text/html
c.redirect('/new-path') // 302 redirect
c.redirect('/new-path', 301) // 301 redirect
c.body('raw body', 200, headers) // raw response
c.notFound() // 404 response
ts
c.text('Hello') // text/plain
c.json({ message: 'Hello' }) // application/json
c.html('<h1>Hello</h1>') // text/html
c.redirect('/new-path') // 302 重定向
c.redirect('/new-path', 301) // 301 重定向
c.body('raw body', 200, headers) // 原始响应
c.notFound() // 404 响应

Headers & Status

请求头与状态码

ts
c.status(201)
c.header('X-Custom', 'value')
c.header('Cache-Control', 'no-store')
ts
c.status(201)
c.header('X-Custom', 'value')
c.header('Cache-Control', 'no-store')

Variables (request-scoped data)

变量(请求作用域数据)

ts
// In middleware
c.set('user', { id: 1, name: 'Alice' })

// In handler
const user = c.get('user')
// or
const user = c.var.user
ts
// 在中间件中
c.set('user', { id: 1, name: 'Alice' })

// 在处理器中
const user = c.get('user')
// 或
const user = c.var.user

Environment (Cloudflare Workers)

环境(Cloudflare Workers)

ts
const value = await c.env.KV.get('key')
const db = c.env.DATABASE
c.executionCtx.waitUntil(promise)
ts
const value = await c.env.KV.get('key')
const db = c.env.DATABASE
c.executionCtx.waitUntil(promise)

Renderer

渲染器

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

app.get('/', (c) => c.render(<h1>Hello</h1>))

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

app.get('/', (c) => c.render(<h1>Hello</h1>))

HonoRequest (c.req)

HonoRequest (c.req)

ts
c.req.param('id') // path parameter
c.req.param() // all path params as object
c.req.query('page') // query string parameter
c.req.query() // all query params as object
c.req.queries('tags') // multiple values: ?tags=A&tags=B → ['A', 'B']
c.req.header('Authorization') // request header
c.req.header() // all headers (keys are lowercase)

// Body parsing
await c.req.json() // parse JSON body
await c.req.text() // parse text body
await c.req.formData() // parse as FormData
await c.req.parseBody() // parse multipart/form-data or urlencoded
await c.req.arrayBuffer() // parse as ArrayBuffer
await c.req.blob() // parse as Blob

// Validated data (used with validator middleware)
c.req.valid('json')
c.req.valid('query')
c.req.valid('form')
c.req.valid('param')

// Properties
c.req.url // full URL string
c.req.path // pathname
c.req.method // HTTP method
c.req.raw // underlying Request object

ts
c.req.param('id') // 路径参数
c.req.param() // 所有路径参数组成的对象
c.req.query('page') // 查询字符串参数
c.req.query() // 所有查询参数组成的对象
c.req.queries('tags') // 多值参数:?tags=A&tags=B → ['A', 'B']
c.req.header('Authorization') // 请求头
c.req.header() // 所有请求头(键为小写)

// 请求体解析
await c.req.json() // 解析JSON请求体
await c.req.text() // 解析文本请求体
await c.req.formData() // 解析为FormData
await c.req.parseBody() // 解析multipart/form-data或urlencoded格式
await c.req.arrayBuffer() // 解析为ArrayBuffer
await c.req.blob() // 解析为Blob

// 验证后的数据(与validator中间件配合使用)
c.req.valid('json')
c.req.valid('query')
c.req.valid('form')
c.req.valid('param')

// 属性
c.req.url // 完整URL字符串
c.req.path // 路径名
c.req.method // HTTP方法
c.req.raw // 底层Request对象

Middleware

中间件

Using Built-in Middleware

使用内置中间件

ts
import { cors } from 'hono/cors'
import { logger } from 'hono/logger'
import { basicAuth } from 'hono/basic-auth'
import { prettyJSON } from 'hono/pretty-json'
import { secureHeaders } from 'hono/secure-headers'
import { etag } from 'hono/etag'
import { compress } from 'hono/compress'
import { poweredBy } from 'hono/powered-by'
import { timing } from 'hono/timing'
import { cache } from 'hono/cache'
import { bearerAuth } from 'hono/bearer-auth'
import { jwt } from 'hono/jwt'
import { jwk } from 'hono/jwk'
import { csrf } from 'hono/csrf'
import { ipRestriction } from 'hono/ip-restriction'
import { bodyLimit } from 'hono/body-limit'
import { timeout } from 'hono/timeout'
import { requestId } from 'hono/request-id'
import { methodOverride } from 'hono/method-override'
import { methodNotAllowed } from 'hono/method-not-allowed'
import { languageDetector } from 'hono/language'
import { some, every, except } from 'hono/combine'
import { contextStorage, getContext } from 'hono/context-storage'
import { trailingSlash, trimTrailingSlash } from 'hono/trailing-slash'

// Registration
app.use(logger()) // all routes
app.use('/api/*', cors()) // specific path
app.post('/api/*', basicAuth({ username: 'admin', password: 'secret' }))
ts
import { cors } from 'hono/cors'
import { logger } from 'hono/logger'
import { basicAuth } from 'hono/basic-auth'
import { prettyJSON } from 'hono/pretty-json'
import { secureHeaders } from 'hono/secure-headers'
import { etag } from 'hono/etag'
import { compress } from 'hono/compress'
import { poweredBy } from 'hono/powered-by'
import { timing } from 'hono/timing'
import { cache } from 'hono/cache'
import { bearerAuth } from 'hono/bearer-auth'
import { jwt } from 'hono/jwt'
import { jwk } from 'hono/jwk'
import { csrf } from 'hono/csrf'
import { ipRestriction } from 'hono/ip-restriction'
import { bodyLimit } from 'hono/body-limit'
import { timeout } from 'hono/timeout'
import { requestId } from 'hono/request-id'
import { methodOverride } from 'hono/method-override'
import { methodNotAllowed } from 'hono/method-not-allowed'
import { languageDetector } from 'hono/language'
import { some, every, except } from 'hono/combine'
import { contextStorage, getContext } from 'hono/context-storage'
import { trailingSlash, trimTrailingSlash } from 'hono/trailing-slash'

// 注册
app.use(logger()) // 所有路由
app.use('/api/*', cors()) // 指定路径
app.post('/api/*', basicAuth({ username: 'admin', password: 'secret' }))

Custom Middleware

自定义中间件

ts
// Inline
app.use(async (c, next) => {
  const start = Date.now()
  await next()
  const elapsed = Date.now() - start
  c.res.headers.set('X-Response-Time', `${elapsed}ms`)
})

// Reusable with createMiddleware
import { createMiddleware } from 'hono/factory'

const auth = createMiddleware(async (c, next) => {
  const token = c.req.header('Authorization')
  if (!token) return c.json({ error: 'Unauthorized' }, 401)
  await next()
})

app.use('/api/*', auth)
ts
// 内联方式
app.use(async (c, next) => {
  const start = Date.now()
  await next()
  const elapsed = Date.now() - start
  c.res.headers.set('X-Response-Time', `${elapsed}ms`)
})

// 使用createMiddleware创建可复用中间件
import { createMiddleware } from 'hono/factory'

const auth = createMiddleware(async (c, next) => {
  const token = c.req.header('Authorization')
  if (!token) return c.json({ error: 'Unauthorized' }, 401)
  await next()
})

app.use('/api/*', auth)

Middleware Execution Order

中间件执行顺序

Middleware executes in registration order.
await next()
calls the next middleware/handler, and code after
next()
runs on the way back:
Request → mw1 before → mw2 before → handler → mw2 after → mw1 after → Response
ts
app.use(async (c, next) => {
  // before handler
  await next()
  // after handler
})

中间件按注册顺序执行。
await next()
调用下一个中间件/处理器,
next()
之后的代码在返回阶段运行:
请求 → mw1 前置逻辑 → mw2 前置逻辑 → 处理器 → mw2 后置逻辑 → mw1 后置逻辑 → 响应
ts
app.use(async (c, next) => {
  // 处理器执行前的逻辑
  await next()
  // 处理器执行后的逻辑
})

Validation

验证

Validation targets:
json
,
form
,
query
,
header
,
param
,
cookie
.
验证目标:
json
form
query
header
param
cookie

Zod Validator

Zod 验证器

ts
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'

const schema = z.object({
  title: z.string().min(1),
  body: z.string()
})

app.post('/posts', zValidator('json', schema), (c) => {
  const data = c.req.valid('json') // fully typed
  return c.json(data, 201)
})
ts
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'

const schema = z.object({
  title: z.string().min(1),
  body: z.string()
})

app.post('/posts', zValidator('json', schema), (c) => {
  const data = c.req.valid('json') // 完全类型化
  return c.json(data, 201)
})

Valibot / Standard Schema Validator

Valibot / 标准 Schema 验证器

ts
import { sValidator } from '@hono/standard-validator'
import * as v from 'valibot'

const schema = v.object({ name: v.string(), age: v.number() })

app.post('/users', sValidator('json', schema), (c) => {
  const data = c.req.valid('json')
  return c.json(data, 201)
})

ts
import { sValidator } from '@hono/standard-validator'
import * as v from 'valibot'

const schema = v.object({ name: v.string(), age: v.number() })

app.post('/users', sValidator('json', schema), (c) => {
  const data = c.req.valid('json')
  return c.json(data, 201)
})

JSX

JSX

Setup

配置

In
tsconfig.json
:
json
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "hono/jsx"
  }
}
Or use pragma:
/** @jsxImportSource hono/jsx */
Important: Files using JSX must have a
.tsx
extension. Rename
.ts
to
.tsx
or the compiler will fail.
tsconfig.json
中:
json
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "hono/jsx"
  }
}
或使用编译指令:
/** @jsxImportSource hono/jsx */
重要提示: 使用JSX的文件必须使用
.tsx
扩展名。将
.ts
重命名为
.tsx
,否则编译会失败。

Components

组件

tsx
import type { PropsWithChildren } from 'hono/jsx'

const Layout = (props: PropsWithChildren) => (
  <html>
    <head>
      <title>My App</title>
    </head>
    <body>{props.children}</body>
  </html>
)

const UserCard = ({ name }: { name: string }) => (
  <div class="card">
    <h2>{name}</h2>
  </div>
)

app.get('/', (c) => {
  return c.html(
    <Layout>
      <UserCard name="Alice" />
    </Layout>
  )
})
tsx
import type { PropsWithChildren } from 'hono/jsx'

const Layout = (props: PropsWithChildren) => (
  <html>
    <head>
      <title>My App</title>
    </head>
    <body>{props.children}</body>
  </html>
)

const UserCard = ({ name }: { name: string }) => (
  <div class="card">
    <h2>{name}</h2>
  </div>
)

app.get('/', (c) => {
  return c.html(
    <Layout>
      <UserCard name="Alice" />
    </Layout>
  )
})

jsxRenderer Middleware

jsxRenderer 中间件

Use
jsxRenderer
middleware for layouts. For details, see https://hono.dev/docs/middleware/builtin/jsx-renderer
使用
jsxRenderer
中间件实现布局。详情请见https://hono.dev/docs/middleware/builtin/jsx-renderer

Async Components

异步组件

tsx
const UserList = async () => {
  const users = await fetchUsers()
  return (
    <ul>
      {users.map((u) => (
        <li>{u.name}</li>
      ))}
    </ul>
  )
}
tsx
const UserList = async () => {
  const users = await fetchUsers()
  return (
    <ul>
      {users.map((u) => (
        <li>{u.name}</li>
      ))}
    </ul>
  )
}

Fragments

片段

tsx
const Items = () => (
  <>
    <li>Item 1</li>
    <li>Item 2</li>
  </>
)

tsx
const Items = () => (
  <>
    <li>Item 1</li>
    <li>Item 2</li>
  </>
)

Streaming

流式传输

ts
import { stream, streamText, streamSSE } from 'hono/streaming'

// Basic stream
app.get('/stream', (c) => {
  return stream(c, async (stream) => {
    stream.onAbort(() => console.log('Aborted'))
    await stream.write(new Uint8Array([0x48, 0x65]))
    await stream.pipe(readableStream)
  })
})

// Text stream
app.get('/stream-text', (c) => {
  return streamText(c, async (stream) => {
    await stream.writeln('Hello')
    await stream.sleep(1000)
    await stream.write('World')
  })
})

// Server-Sent Events
app.get('/sse', (c) => {
  return streamSSE(c, async (stream) => {
    let id = 0
    while (true) {
      await stream.writeSSE({
        data: JSON.stringify({ time: new Date().toISOString() }),
        event: 'time-update',
        id: String(id++)
      })
      await stream.sleep(1000)
    }
  })
})

ts
import { stream, streamText, streamSSE } from 'hono/streaming'

// 基础流式传输
app.get('/stream', (c) => {
  return stream(c, async (stream) => {
    stream.onAbort(() => console.log('Aborted'))
    await stream.write(new Uint8Array([0x48, 0x65]))
    await stream.pipe(readableStream)
  })
})

// 文本流式传输
app.get('/stream-text', (c) => {
  return streamText(c, async (stream) => {
    await stream.writeln('Hello')
    await stream.sleep(1000)
    await stream.write('World')
  })
})

// 服务器发送事件(SSE)
app.get('/sse', (c) => {
  return streamSSE(c, async (stream) => {
    let id = 0
    while (true) {
      await stream.writeSSE({
        data: JSON.stringify({ time: new Date().toISOString() }),
        event: 'time-update',
        id: String(id++)
      })
      await stream.sleep(1000)
    }
  })
})

Testing with app.request()

使用app.request()进行测试

Test endpoints without starting an HTTP server:
ts
// GET
const res = await app.request('/posts')
expect(res.status).toBe(200)
expect(await res.json()).toEqual({ posts: [] })

// POST with JSON
const res = await app.request('/posts', {
  method: 'POST',
  body: JSON.stringify({ title: 'Hello' }),
  headers: { 'Content-Type': 'application/json' }
})

// POST with FormData
const formData = new FormData()
formData.append('name', 'Alice')
const res = await app.request('/users', { method: 'POST', body: formData })

// With mock env (Cloudflare Workers bindings)
const res = await app.request('/api/data', {}, { KV: mockKV, DATABASE: mockDB })

// Using Request object
const req = new Request('http://localhost/api', { method: 'DELETE' })
const res = await app.request(req)

无需启动HTTP服务器即可测试端点:
ts
// GET
const res = await app.request('/posts')
expect(res.status).toBe(200)
expect(await res.json()).toEqual({ posts: [] })

// 带JSON的POST请求
const res = await app.request('/posts', {
  method: 'POST',
  body: JSON.stringify({ title: 'Hello' }),
  headers: { 'Content-Type': 'application/json' }
})

// 带FormData的POST请求
const formData = new FormData()
formData.append('name', 'Alice')
const res = await app.request('/users', { method: 'POST', body: formData })

// 带模拟环境(Cloudflare Workers绑定)
const res = await app.request('/api/data', {}, { KV: mockKV, DATABASE: mockDB })

// 使用Request对象
const req = new Request('http://localhost/api', { method: 'DELETE' })
const res = await app.request(req)

Hono Client (RPC)

Hono 客户端(RPC)

Type-safe API client using shared types between server and client.
IMPORTANT: Routes MUST be chained for type inference to work. Without chaining, the client cannot infer route types.
ts
// Server: routes MUST be chained to preserve types
const route = app
  .post('/posts', zValidator('json', schema), (c) => {
    return c.json({ ok: true }, 201)
  })
  .get('/posts', (c) => {
    return c.json({ posts: [] })
  })
export type AppType = typeof route

// Client: use hc() with the exported type
import { hc } from 'hono/client'
import type { AppType } from './server'

const client = hc<AppType>('http://localhost:8787/')
const res = await client.posts.$post({ json: { title: 'Hello' } })
const data = await res.json() // fully typed
Type utilities:
ts
import type { InferRequestType, InferResponseType } from 'hono/client'

type ReqType = InferRequestType<typeof client.posts.$post>
type ResType = InferResponseType<typeof client.posts.$post, 200>

使用服务端与客户端共享类型的类型安全API客户端。
重要提示: 路由必须链式调用才能进行类型推断。不链式调用的话,客户端无法推断路由类型。
ts
// 服务端:路由必须链式调用以保留类型
const route = app
  .post('/posts', zValidator('json', schema), (c) => {
    return c.json({ ok: true }, 201)
  })
  .get('/posts', (c) => {
    return c.json({ posts: [] })
  })
export type AppType = typeof route

// 客户端:使用hc()并传入导出的类型
import { hc } from 'hono/client'
import type { AppType } from './server'

const client = hc<AppType>('http://localhost:8787/')
const res = await client.posts.$post({ json: { title: 'Hello' } })
const data = await res.json() // 完全类型化
类型工具:
ts
import type { InferRequestType, InferResponseType } from 'hono/client'

type ReqType = InferRequestType<typeof client.posts.$post>
type ResType = InferResponseType<typeof client.posts.$post, 200>

Helpers

工具函数

Helpers are utility functions imported from
hono/<helper-name>
:
ts
import { getConnInfo } from 'hono/conninfo'
import { getCookie, setCookie, deleteCookie } from 'hono/cookie'
import { css, Style } from 'hono/css'
import { createFactory } from 'hono/factory'
import { html, raw } from 'hono/html'
import { stream, streamText, streamSSE } from 'hono/streaming'
import { testClient } from 'hono/testing'
import { upgradeWebSocket } from 'hono/cloudflare-workers' // or other adapter
Available helpers: Accepts, Adapter, ConnInfo, Cookie, css, Dev, Factory, html, JWT, Proxy, Route, SSG, Streaming, Testing, WebSocket.
For details, see
https://hono.dev/docs/helpers/<helper-name>
(fetch with
Accept: text/markdown
).
工具函数是从
hono/<helper-name>
导入的实用函数:
ts
import { getConnInfo } from 'hono/conninfo'
import { getCookie, setCookie, deleteCookie } from 'hono/cookie'
import { css, Style } from 'hono/css'
import { createFactory } from 'hono/factory'
import { html, raw } from 'hono/html'
import { stream, streamText, streamSSE } from 'hono/streaming'
import { testClient } from 'hono/testing'
import { upgradeWebSocket } from 'hono/cloudflare-workers' // 或其他适配器
可用工具函数:Accepts、Adapter、ConnInfo、Cookie、css、Dev、Factory、html、JWT、Proxy、Route、SSG、Streaming、Testing、WebSocket。
详情请见
https://hono.dev/docs/helpers/<helper-name>
(通过
Accept: text/markdown
请求获取)。

Factory

Factory

Use
createFactory
to define
Env
once and share it across app, middleware, and handlers:
ts
import { createFactory } from 'hono/factory'

const factory = createFactory<Env>()

// Create app (Env type is inherited)
const app = factory.createApp()

// Create middleware (Env type is inherited, no need to pass generics)
const mw = factory.createMiddleware(async (c, next) => {
  await next()
})

// Create handlers separately (preserves type inference)
const handlers = factory.createHandlers(logger(), (c) => c.json({ message: 'Hello' }))
app.get('/api', ...handlers)

使用
createFactory
一次性定义
Env
,并在应用、中间件和处理器之间共享:
ts
import { createFactory } from 'hono/factory'

const factory = createFactory<Env>()

// 创建应用(继承Env类型)
const app = factory.createApp()

// 创建中间件(继承Env类型,无需传递泛型)
const mw = factory.createMiddleware(async (c, next) => {
  await next()
})

// 单独创建处理器(保留类型推断)
const handlers = factory.createHandlers(logger(), (c) => c.json({ message: 'Hello' }))
app.get('/api', ...handlers)

Best Practices

最佳实践

  • Write handlers inline in route definitions for proper type inference of path params.
  • Use
    app.route()
    to organize large apps by feature, not Rails-style controllers.
  • Use
    createFactory()
    to share Env type across app, middleware, and handlers.
  • Use
    c.set()
    /
    c.get()
    to pass data between middleware and handlers.
  • Chain validators for multiple request parts (param + query + json).
  • Export app type for RPC:
    export type AppType = typeof routes
  • Use
    app.request()
    for testing — no server startup needed.
  • 在路由定义中内联编写处理器,以正确推断路径参数的类型。
  • 使用
    app.route()
    按功能组织大型应用,而非Rails风格的控制器。
  • 使用
    createFactory()
    在应用、中间件和处理器之间共享Env类型。
  • 使用
    c.set()
    /
    c.get()
    在中间件和处理器之间传递数据。
  • 为多个请求部分(参数+查询+json)链式调用验证器。
  • 导出应用类型用于RPC:
    export type AppType = typeof routes
  • 使用
    app.request()
    进行测试——无需启动服务器。

Adapters

适配器

Hono runs on multiple runtimes. The default export works for Cloudflare Workers, Deno, and Bun. For Node.js, use the Node adapter:
ts
// Cloudflare Workers / Deno / Bun
export default app

// Node.js
import { serve } from '@hono/node-server'
serve(app)
Hono可在多种运行时运行。默认导出适用于Cloudflare Workers、Deno和Bun。对于Node.js,请使用Node适配器:
ts
// Cloudflare Workers / Deno / Bun
export default app

// Node.js
import { serve } from '@hono/node-server'
serve(app)