编程 Hono 深度拆解:当 Web 标准决定「干掉全部运行时锁定」——一个 25K Star 的框架如何用 14KB 包体和 RegExpRouter 重新定义边缘计算 Web 开发的终极形态

2026-08-05 07:43:36 +0800 CST views 7

Hono 深度拆解:当 Web 标准决定「干掉全部运行时锁定」——一个 25K Star 的框架如何用 14KB 包体和 RegExpRouter 重新定义边缘计算 Web 开发的终极形态

引言:Express 的困局与 Hono 的诞生

2022 年,Cloudflare Workers 在全球 CDN 节点上跑起了 JavaScript。Vercel 推出了 Edge Runtime。Deno 和 Bun 相继崛起。JavaScript 运行时从「Node.js 一家独大」变成了「百花齐放」的格局。

但问题来了:Express 这个统治了 Node.js 十余年的 Web 框架,跑在这些新运行时上全是坑。

Express 的中间件基于 Node.js 的 req/res 对象模型设计,依赖 streamBufferfs 等 Node.js 专有 API。当你试图把一个 Express 应用部署到 Cloudflare Workers 时,会发现:

  • app.listen() 在 Workers 里根本不存在(Workers 没有 TCP 监听器)
  • req.body 的流式处理方式和 Workers 的 ReadableStream 不兼容
  • 中间件链的错误处理机制依赖 Node.js 的事件循环模型
  • connect/express 的中间件签名 (req, res, next) 和 Web 标准的 Request/Response 完全是两套体系

于是日本开发者 Yusuke Wada 做了一个决定:既然现有框架都是为特定运行时设计的,那就造一个只基于 Web 标准的框架。

Hono(日语「火焰🔥」)就此诞生。它的核心理念极其简单:

用 Web Standard APIs 构建,跑在任何 JavaScript 运行时上。

这个「简单」的理念,让它在 2026 年拿下了 25K+ GitHub Star,成为边缘计算领域事实上的标准框架。

一、架构全景:14KB 的极致设计

1.1 包体分析:hono/tiny 为什么能这么小

Hono 的最小预设 hono/tiny 只有 14KB(gzipped)。对比一下:

框架包体大小(gzip)依赖数
Hono (tiny)14KB0
Express203KB62
Fastify89KB34
Koa62KB19
Hapi147KB47

0 依赖。不是「核心依赖少」,是真正的零依赖。Hono 的所有功能——路由、中间件、验证、JWT、CORS——全部是框架内部实现,不依赖任何第三方包。

这意味着:

  • 无供应链安全风险:没有 node_modules 里的 2000+ 间接依赖
  • 无版本冲突:不会出现「A 包需要 lodash@4,B 包需要 lodash@3」的地狱
  • 极速安装npm install hono 几乎瞬间完成

1.2 路由引擎:RegExpRouter 的 O(1) 秘密

Hono 的路由系统有三个层级:

RegExpRouter(默认,最快)
    ↓ fallback
TrieRouter(内存更优,支持通配符)
    ↓ fallback
SmartRouter(自动选择最优策略)

RegExpRouter 的核心思路是:在启动时把所有路由规则编译成一个巨型正则表达式。每次请求进来,只需要一次 RegExp.exec() 调用就能匹配到正确的路由。

这和 Express 的逐条遍历完全不同。Express 的路由匹配是 O(n)——n 是路由数量,100 条路由就要最多比较 100 次。RegExpRouter 是 O(1)——无论多少条路由,匹配时间恒定。

来看实际的基准测试数据(Cloudflare Workers,M1 Pro):

Hono x 402,820 ops/sec ±4.78%
itty-router x 212,598 ops/sec ±3.11%
sunder x 297,036 ops/sec ±4.76%
worktop x 197,345 ops/sec ±2.40%

Hono 的吞吐量是 itty-router 的 1.9 倍,是 worktop 的 2.0 倍。在 Deno 上的测试更夸张:

框架版本请求数/秒
Hono3.0.0136,112
Fast4.0.0-beta.1103,214
Megalo0.3.064,597
oak10.5.143,326

Hono 在 Deno 上的性能是 oak 的 3.1 倍

1.3 Web Standards:真正的运行时无关

Hono 的每一个 API 都基于 Web 标准:

  • Request / Response — Web Fetch API
  • ReadableStream / WritableStream — Web Streams API
  • Headers / URL / URLPattern — Web 标准
  • crypto.subtle — Web Crypto API

没有 req.headers.host 这种 Node.js 专有写法,只有 request.headers.get('host')

这带来的好处是:同一份代码,不修改任何一行,可以直接部署到 Cloudflare Workers、Deno Deploy、Bun、AWS Lambda、Vercel Edge、Node.js。

Hono 官方支持的运行时列表:

Cloudflare Workers / Pages
Deno
Bun
Vercel
Netlify
AWS Lambda / Lambda@Edge
Fastly Compute
Google Cloud Run
Azure Functions
Ali Function Compute(阿里云函数计算)
Node.js
WebAssembly (WASI)
Service Worker

12 个运行时。一份代码。零改动。

二、核心特性深度拆解

2.1 RPC:前后端共享类型的终极方案

Hono 最杀手级的特性是 RPC(Remote Procedure Call)——前端可以直接调用后端的 API,类型自动推导,零 API 文档,零代码生成

传统方式下,前后端联调 API 需要:

  1. 后端写 Swagger/OpenAPI 文档
  2. 前端用 openapi-typescript 之类的工具生成类型
  3. 手动维护接口契约,文档过期了就炸

Hono 的 RPC 彻底消灭了这个流程:

服务端代码:

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

const app = new Hono()

const route = app.post(
  '/posts',
  zValidator(
    'form',
    z.object({
      title: z.string(),
      body: z.string(),
    })
  ),
  (c) => {
    return c.json(
      { ok: true, message: 'Created!' },
      201
    )
  }
)

// 导出类型——这是 RPC 的关键
export type AppType = typeof route

客户端代码:

import type { AppType } from './server'
import { hc } from 'hono/client'

const client = hc<AppType>('http://localhost:8787/')

// 类型完全自动推导!
// client.posts.$post 的参数类型 = { form: { title: string; body: string } }
// 返回类型 = { ok: boolean; message: string }
const res = await client.posts.$post({
  form: {
    title: 'Hello',
    body: 'Hono is a cool project',
  },
})

if (res.ok) {
  const data = await res.json()
  // data 的类型自动推导为 { ok: true; message: string }
  console.log(data.message) // TypeScript 完全支持
}

零代码生成。零 API 文档维护。类型安全贯穿前后端。

更强大的是,RPC 还支持按状态码推导类型:

// 服务端:返回不同状态码不同结构
const route = app.get('/posts/:id', async (c) => {
  const post = await getPost(c.req.param('id'))
  if (!post) {
    return c.json({ error: 'not found' }, 404)  // 类型 1
  }
  return c.json({ post }, 200)  // 类型 2
})

// 客户端:按 status 码区分类型
const res = await client.posts[':id'].$get({
  param: { id: '123' },
})

if (res.status === 404) {
  const data: { error: string } = await res.json()
} else if (res.ok) {
  const data: { post: Post } = await res.json()
}

2.2 JSX 支持:不只是 React,是全栈 JSX

Hono 内置了 JSX 支持,但不是 React 的 JSX——它是一个轻量级的、服务端渲染优化的 JSX 引擎

import { Hono } from 'hono'
import { html } from 'hono/html'

const app = new Hono()

// 使用 html 标签——自动转义 XSS
app.get('/', (c) => {
  const name = c.req.query('name') || 'World'
  return c.html(html`
    <!DOCTYPE html>
    <html>
      <head><title>Hono SSR</title></head>
      <body>
        <h1>Hello, ${name}!</h1>
        <p>This is server-rendered HTML.</p>
      </body>
    </html>
  `)
})

// JSX 组件
const Layout = ({ children }: { children: any }) => html`
  <html>
    <head><title>My App</title></head>
    <body>${children}</body>
  </html>
`

const Hello = ({ name }: { name: string }) => html`
  <h1>Hello, ${name}!</h1>
`

app.get('/jsx', (c) => {
  return c.html(
    <Layout>
      <Hello name="Hono" />
    </Layout>
  )
})

export default app

注意和 React JSX 的区别:

  • Hono 的 JSX 编译后生成 html tagged template string,不创建虚拟 DOM
  • 输出是纯 HTML 字符串,直接发送给客户端
  • 性能极高——没有 diff,没有 reconciliation,纯字符串拼接

这让 Hono 成为 轻量级 SSR 的理想选择。一个 API 服务 + 管理后台,同一个框架搞定。

2.3 OpenAPI 自动生成

Hono 配合 @hono/zod-validator 可以自动生成 OpenAPI/Swagger 文档

import { Hono } from 'hono'
import { z } from 'zod'
import { zValidator } from '@hono/zod-validator'
import { swaggerUI } from '@hono/swagger-ui'
import { OpenAPIHono } from '@hono/zod-openapi'

const app = new OpenAPIHono()

// 定义 OpenAPI schema
const PostSchema = z.object({
  id: z.string().openapi({ example: '123' }),
  title: z.string().openapi({ example: 'Hello World' }),
  body: z.string().openapi({ example: 'This is a post.' }),
})

const CreatePostSchema = z.object({
  title: z.string().min(1).openapi({ example: 'Hello World' }),
  body: z.string().min(1).openapi({ example: 'This is a post.' }),
})

// 路由定义即文档
app.openapi(
  {
    method: 'post',
    path: '/posts',
    tags: ['Posts'],
    summary: 'Create a post',
    request: {
      body: {
        required: true,
        content: {
          'application/json': {
            schema: CreatePostSchema,
          },
        },
      },
    },
    responses: {
      201: {
        content: {
          'application/json': {
            schema: PostSchema,
          },
        },
        description: 'Created',
      },
    },
  },
  (c) => {
    const body = c.req.valid('json')
    // body 的类型自动推导
    return c.json({ id: '1', ...body }, 201)
  }
)

// 自动生成 OpenAPI JSON
app.doc('/openapi.json', {
  openapi: '3.0.0',
  info: {
    title: 'My API',
    version: '1.0.0',
  },
})

// Swagger UI
app.get('/docs', swaggerUI({ url: '/openapi.json' }))

export default app

写一次路由定义,同时得到类型安全的 RPC 客户端和完整的 OpenAPI 文档。

2.4 中间件体系:洋葱模型 + 类型安全

Hono 的中间件采用经典的洋葱模型(Onion Model),但有一个关键区别:中间件链中的类型是流动的

import { Hono } from 'hono'
import { cors } from 'hono/cors'
import { jwt } from 'hono/jwt'
import { prettyJSON } from 'hono/pretty-json'
import { logger } from 'hono/logger'

const app = new Hono()

// 内置中间件——全部零依赖
app.use('*', logger())
app.use('*', cors())
app.use('*', prettyJSON())

// JWT 认证中间件
app.use('/api/*', jwt({ secret: 'my-secret' }))

// 自定义中间件——类型安全
const注入用户 = async (c: Context, next: Next) => {
  const token = c.req.header('Authorization')
  if (!token) {
    return c.json({ error: 'Unauthorized' }, 401)
  }
  const user = await verifyToken(token)
  c.set('user', user) // 类型安全地注入
  await next()
}

app.use('/api/admin/*', 注入用户)

// 路由处理函数可以直接访问注入的类型
app.get('/api/admin/profile', (c) => {
  const user = c.get('user') // 类型自动推导!
  return c.json({ user })
})

Hono 内置了 20+ 中间件,全部零依赖:

basic-auth, bearer-auth, body-limit, cache, combine,
compress, context-storage, cors, csrf, etag,
ip-restriction, jsx-renderer, jwk, jwt, language,
logger, method-not-allowed, method-override, pretty-json,
request-id, secure-headers, timeout, timing, trailing-slash

对比 Express——内置中间件只有 express.json()express.urlencoded(),其他全靠第三方。

2.5 类型系统:Hono 的「Types」

Hono 5.x 引入了全新的类型推导系统,核心是 hc(Hono Client)和一系列类型工具:

import type {
  InferRequestType,
  InferResponseType,
  ClientRequest,
} from 'hono/client'

// 从 RPC 路由推导请求类型
type CreatePostReq = InferRequestType<
  typeof client.posts.$post
>['form']
// { title: string; body: string }

// 从 RPC 路由推导响应类型
type PostRes = InferResponseType<
  typeof client.posts.$get
>
// { post: Post } | { error: string }

// 按状态码推导响应类型
type PostRes200 = InferResponseType<
  typeof client.posts.$get,
  200
>
// { post: Post }

这意味着你可以在前端完全不看 API 文档的情况下写出类型安全的代码。TypeScript 编辑器会告诉你每个请求需要什么参数、返回什么结构。

三、实战:从零构建一个生产级 API

3.1 项目初始化

npm create hono@latest my-api
# 选择 cloudflare-workers 模板

cd my-api
npm install
npm install zod @hono/zod-validator @hono/zod-openapi @hono/swagger-ui

3.2 完整项目结构

my-api/
├── src/
│   ├── index.ts          # 入口
│   ├── routes/
│   │   ├── posts.ts      # 帖子路由
│   │   └── users.ts      # 用户路由
│   ├── middleware/
│   │   ├── auth.ts       # 认证中间件
│   │   └── rate-limit.ts # 限流中间件
│   ├── schema/
│   │   └── posts.ts      # Zod schema
│   └── lib/
│       └── db.ts         # 数据库连接
├── wrangler.jsonc
└── package.json

3.3 路由层:类型安全的 CRUD

// src/routes/posts.ts
import { OpenAPIHono, createRoute } from '@hono/zod-openapi'
import { z } from 'zod'
import { zValidator } from '@hono/zod-validator'

const app = new OpenAPIHono()

// === Schema 定义 ===
const PostSchema = z.object({
  id: z.string().openapi({ example: 'post_001' }),
  title: z.string().openapi({ example: '深入理解 Hono' }),
  content: z.string().openapi({ example: 'Hono 是一个...' }),
  authorId: z.string().openapi({ example: 'user_001' }),
  createdAt: z.string().datetime().openapi({ example: '2026-08-05T07:00:00Z' }),
})

const CreatePostSchema = z.object({
  title: z.string().min(1).max(200).openapi({ example: '深入理解 Hono' }),
  content: z.string().min(1).max(10000).openapi({ example: 'Hono 是一个...' }),
})

const QuerySchema = z.object({
  page: z.coerce.number().min(1).default(1).openapi({ example: 1 }),
  limit: z.coerce.number().min(1).max(100).default(20).openapi({ example: 20 }),
  search: z.string().optional().openapi({ example: 'hono' }),
})

// === 路由定义 ===
const listRoute = createRoute({
  method: 'get',
  path: '/posts',
  tags: ['Posts'],
  summary: '获取帖子列表',
  request: { query: QuerySchema },
  responses: {
    200: {
      content: {
        'application/json': {
          schema: z.object({
            posts: z.array(PostSchema),
            total: z.number(),
            page: z.number(),
          }),
        },
      },
      description: '帖子列表',
    },
  },
})

app.openapi(listRoute, async (c) => {
  const { page, limit, search } = c.req.valid('query')
  const db = c.get('db')

  const where = search
    ? { title: { contains: search } }
    : {}

  const [posts, total] = await Promise.all([
    db.post.findMany({
      where,
      skip: (page - 1) * limit,
      take: limit,
      orderBy: { createdAt: 'desc' },
    }),
    db.post.count({ where }),
  ])

  return c.json({ posts, total, page })
})

// 创建帖子
const createRoute = createRoute({
  method: 'post',
  path: '/posts',
  tags: ['Posts'],
  summary: '创建帖子',
  request: {
    body: {
      required: true,
      content: { 'application/json': { schema: CreatePostSchema } },
    },
  },
  responses: {
    201: {
      content: {
        'application/json': { schema: PostSchema },
      },
      description: '帖子创建成功',
    },
    400: {
      description: '参数错误',
    },
  },
})

app.openapi(createRoute, async (c) => {
  const body = c.req.valid('json')
  const user = c.get('user') // 来自 auth 中间件
  const db = c.get('db')

  const post = await db.post.create({
    data: {
      ...body,
      authorId: user.id,
      createdAt: new Date().toISOString(),
    },
  })

  return c.json(post, 201)
})

// 导出类型供 RPC 使用
export type PostRoutes = typeof app

3.4 中间件层:认证与限流

// src/middleware/auth.ts
import { MiddlewareHandler } from 'hono'
import { jwt } from 'hono/jwt'

export const authMiddleware: MiddlewareHandler = async (c, next) => {
  const token = c.req.header('Authorization')?.replace('Bearer ', '')
  if (!token) {
    return c.json({ error: 'Missing token' }, 401)
  }

  try {
    const payload = await jwt.verify(token, c.env.JWT_SECRET)
    c.set('user', payload as JWTPayload)
    await next()
  } catch {
    return c.json({ error: 'Invalid token' }, 401)
  }
}

// src/middleware/rate-limit.ts
const requests = new Map<string, number[]>()

export const rateLimit = (maxRequests: number, windowMs: number): MiddlewareHandler =>
  async (c, next) => {
    const ip = c.req.header('CF-Connecting-IP') || 'unknown'
    const now = Date.now()
    const timestamps = requests.get(ip) || []

    // 清除过期记录
    const valid = timestamps.filter((t) => now - t < windowMs)

    if (valid.length >= maxRequests) {
      return c.json(
        { error: 'Too many requests' },
        429
      )
    }

    valid.push(now)
    requests.set(ip, valid)
    await next()
  }

3.5 入口文件:组装一切

// src/index.ts
import { OpenAPIHono } from '@hono/zod-openapi'
import { swaggerUI } from '@hono/swagger-ui'
import { cors } from 'hono/cors'
import { logger } from 'hono/logger'
import { prettyJSON } from 'hono/pretty-json'

import { postRoutes } from './routes/posts'
import { userRoutes } from './routes/users'
import { authMiddleware } from './middleware/auth'
import { rateLimit } from './middleware/rate-limit'

const app = new OpenAPIHono()

// === 全局中间件 ===
app.use('*', logger())
app.use('*', cors({ origin: '*' }))
app.use('*', prettyJSON())
app.use('/api/*', rateLimit(100, 60 * 1000)) // 100 次/分钟

// === 路由挂载 ===
app.route('/api', postRoutes)
app.route('/api', userRoutes)

// === OpenAPI 文档 ===
app.doc('/openapi.json', {
  openapi: '3.0.0',
  info: {
    title: 'My API',
    version: '1.0.0',
    description: '基于 Hono 的生产级 API',
  },
})

app.get('/docs', swaggerUI({ url: '/openapi.json' }))

// === 健康检查 ===
app.get('/health', (c) =>
  c.json({ status: 'ok', timestamp: new Date().toISOString() })
)

export default app

3.6 前端使用 RPC 调用

// 前端代码(可以是 React/Vue/Svelte/纯 JS)
import type { PostRoutes } from '../server/routes/posts'
import { hc } from 'hono/client'

const client = hc<PostRoutes>('https://my-api.example.com/api')

// 获取帖子列表——类型完全自动推导
const { posts, total } = await client.posts.$get({
  query: { page: 1, limit: 20, search: 'hono' },
}).then((r) => r.json())

// 创建帖子——参数类型自动检查
const newPost = await client.posts.$post({
  json: {
    title: 'Hono 实战指南',
    content: '这是一篇关于 Hono 的深度文章...',
  },
}).then((r) => r.json())

四、性能优化:Hono 的极致调优

4.1 路由性能优化

1. 使用 RegExpRouter(默认)

RegExpRouter 在大多数场景下是最快的。但如果你的路由包含大量通配符(*),TrieRouter 可能更优:

import { Hono } from 'hono'
import { RegExpRouter } from 'hono/router/reg-exp-router'
import { TrieRouter } from 'hono/router/trie-router'

// 默认使用 RegExpRouter
const app = new Hono()

// 或者显式指定
const app2 = new Hono({ router: new RegExpRouter() })

2. 避免动态路由过多

每条动态路由(/users/:id)都会增加正则表达式的复杂度。如果动态路由超过 1000 条,考虑:

// 不好:1000 条独立路由
app.get('/users/:id', handler)
app.get('/posts/:id', handler)
app.get('/comments/:id', handler)
// ... 1000 条

// 好:合并为一条通配符路由
app.get('/:resource/:id', async (c) => {
  const resource = c.req.param('resource')
  const id = c.req.param('id')
  // 按 resource 分发
})

3. 预热路由

如果使用 RegExpRouter,首次请求会触发正则编译。可以在启动时预热:

// Cloudflare Workers: scheduled handler
export default {
  fetch: app.fetch,
  scheduled: async (event, env) => {
    // 预热路由
    await app.request('http://localhost/health')
    console.log('Routes warmed up')
  },
}

4.2 中间件性能优化

1. 减少中间件层级

每多一层中间件,就多一次函数调用开销。在边缘计算场景下,每一次调用都意味着额外的延迟:

// 不好:过多中间件
app.use('*', logger())
app.use('*', cors())
app.use('*', compress())
app.use('*', etag())
app.use('*', secureHeaders())
app.use('*', timing())
app.use('*', requestId())

// 好:按需使用
app.use('*', logger())
app.use('*', cors())
// 其他中间件只在需要的路由上挂载

2. 使用 c.set() / c.get() 传递数据

在中间件之间传递数据时,避免使用全局变量或闭包:

// 好:使用 Hono 的 Context
app.use('*', async (c, next) => {
  c.set('requestId', crypto.randomUUID())
  await next()
})

app.get('/', (c) => {
  const requestId = c.get('requestId') // 类型安全
  return c.json({ requestId })
})

4.3 响应优化

1. 流式响应

对于大数据量的 API,使用流式响应避免内存峰值:

app.get('/stream', (c) => {
  const stream = new ReadableStream({
    async start(controller) {
      for (let i = 0; i < 10000; i++) {
        controller.enqueue(
          new TextEncoder().encode(`${i}\n`)
        )
      }
      controller.close()
    },
  })

  return new Response(stream, {
    headers: { 'Content-Type': 'text/plain' },
  })
})

// 或者使用 Hono 的 streaming helper
import { streamSSE } from 'hono/streaming'

app.get('/sse', (c) => {
  return streamSSE(c, async (stream) => {
    for (let i = 0; i < 100; i++) {
      await stream.writeSSE({
        data: JSON.stringify({ count: i }),
        event: 'update',
        id: String(i),
      })
      await stream.sleep(100)
    }
  })
})

2. 缓存策略

import { cache } from 'hono/cache'

// 内存缓存(适合单实例)
app.get(
  '/data',
  cache({
    cacheControl: 'max-age=3600',
    keyGenerator: (c) => c.req.url,
  }),
  async (c) => {
    const data = await expensiveQuery()
    return c.json(data)
  }
)

// 使用 KV 缓存(适合分布式)
app.get('/kv-data', async (c) => {
  const cacheKey = `data:${c.req.url}`
  const cached = await c.env.KV.get(cacheKey, 'json')
  if (cached) return c.json(cached)

  const data = await expensiveQuery()
  await c.env.KV.put(cacheKey, JSON.stringify(data), {
    expirationTtl: 3600,
  })
  return c.json(data)
})

五、Hono vs 竞品:何时选择谁?

5.1 对比矩阵

特性HonoExpressFastifyElysia (Bun)
包体大小14KB203KB89KB~30KB
运行时支持12+Node.jsNode.jsBun 专有
TypeScript原生需 @types原生原生
RPC 类型安全
OpenAPI 生成需插件需插件需插件
内置中间件数20+215+~10
基准性能⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
边缘计算原生支持需适配需适配Bun 专有

5.2 选型建议

选 Hono 当你需要:

  • 部署到多个运行时(Cloudflare + AWS + Vercel)
  • 前后端类型共享(RPC)
  • 自动 OpenAPI 文档
  • 极致的包体大小
  • 边缘计算场景

选 Express 当你需要:

  • 最大的生态和社区
  • 大量现成的中间件
  • 团队只熟悉 Express
  • 纯 Node.js 部署

选 Fastify 当你需要:

  • 高性能 JSON 序列化
  • 插件系统
  • Schema 验证
  • 纯 Node.js 部署

选 Elysia 当你需要:

  • Bun 专有优化
  • WebSocket 优先的应用
  • 极致的类型安全(Bun + Elysia)

六、迁移指南:Express → Hono

6.1 路由迁移

// Express
app.get('/users/:id', (req, res) => {
  const { id } = req.params
  res.json({ id })
})

// Hono
app.get('/users/:id', (c) => {
  const id = c.req.param('id')
  return c.json({ id })
})

6.2 中间件迁移

// Express
app.use(express.json())
app.use((req, res, next) => {
  console.log(`${req.method} ${req.path}`)
  next()
})

// Hono
app.use('*', (c, next) => {
  // Hono 的 Body 解析自动处理
  return next()
})
app.use('*', logger())

6.3 错误处理迁移

// Express
app.use((err, req, res, next) => {
  console.error(err.stack)
  res.status(500).json({ error: 'Something broke!' })
})

// Hono
app.onError((err, c) => {
  console.error(err.stack)
  return c.json({ error: 'Something broke!' }, 500)
})

七、生态与社区

7.1 官方生态

Hono 的生态由 honojs GitHub 组织维护:

  • hono — 核心框架
  • hono/middleware — 官方中间件仓库(Zod Validator、Valibot、Swagger UI 等)
  • hono/website — 文档站

7.2 第三方生态

  • @hono/zod-openapi — OpenAPI 自动生成
  • @hono/swagger-ui — Swagger UI 中间件
  • hono-react-renderer — React SSR 集成
  • drizzle-orm — 类型安全 ORM(完美配合 Hono)

7.3 谁在用 Hono?

  • Cloudflare — 官方推荐的 Workers 框架
  • Vercel — Edge Runtime 原生支持
  • Supabase — Edge Functions 底层
  • Shopify — Hydrogen 2.0 的部分组件

总结:Web 标准的胜利

Hono 的成功不是因为它做了什么花哨的事情,恰恰相反——它什么都没发明

它没有发明新的运行时(那是 Bun 和 Deno 的事),没有发明新的协议(那是 Web Standards 的事),没有发明新的编程范式(那是 JavaScript 的事)。

它只是做了一件正确的事情:忠于 Web 标准

在一个「框架为运行时服务」的时代,Hono 选择「运行时为框架服务」。它不绑定任何运行时,所以所有运行时都想支持它。它不发明任何 API,所以所有 API 都天然兼容它。

14KB 的包体,0 依赖,12 个运行时,40 万 ops/sec 的路由吞吐量,前后端类型共享的 RPC——这就是「标准」的力量。

Hono 的故事告诉我们:有时候,最好的创新不是发明新东西,而是回归本质。

当所有人都在追逐「更好的运行时」时,Hono 选择做「更好的标准」。结果,标准赢了。


Hono 项目地址:https://github.com/honojs/hono
文档:https://hono.dev
当前 Star 数:25,000+(2026 年 8 月)

推荐文章

#免密码登录服务器
2024-11-19 04:29:52 +0800 CST
ElasticSearch 结构
2024-11-18 10:05:24 +0800 CST
程序员茄子在线接单