Hono 框架入门实战:从开源项目 Hono 开始

一、引言

如果你要构建一个 Web API 服务器,你会选择哪个框架?Express 统治了 Node.js 的 Web 框架市场超过十年,但它的设计是基于 Node.js 的 http 模块,无法在 Cloudflare Workers、Deno 或 Bun 上运行。边缘计算时代,需要新的思路。

Hono------ 一个基于 Web 标准 API 的超轻量 Web 框架,由开发者 Yusuke Wada 创建。它用 14KB 的包大小替代了 Express 的 572KB,同一份代码可以运行在 Cloudflare Workers、Deno、Bun、Node.js 等所有主流运行时上。


二、Hono 开源项目介绍

2.1 项目背景

Hono 由 Yusuke Wada@yusukebe)创建,2022 年首次发布,目前 GitHub 上拥有 30K+ stars,npm 月下载量超过 2 亿次。

核心特性:

特性 说明
Ultrafast RegExpRouter 路由器,基于正则表达式,不依赖线性循环
Lightweight hono/tiny 预设仅 14KB(minified),零依赖
Multi-runtime Cloudflare Workers、Deno、Bun、Node.js、AWS Lambda 等
Web Standards 仅使用 Request/Response/Fetch 等 Web 标准 API
TypeScript 一等公民支持,完整的类型推导

2.2 多运行时架构

2.3 Hono vs Express

维度 Hono Express
包大小 ~14KB ~572KB(40 倍)
运行时 Workers/Deno/Bun/Node Node.js 仅
TypeScript 一等公民 外部类型定义
异步模型 原生 async/await 回调为主
中间件 基于 Web 标准 基于 Node.js http
路由速度 超快(RegExpRouter) 中等(线性匹配)

三、Hono 核心概念

3.1 路由与响应

复制代码
import { Hono } from 'hono'

const app = new Hono()

// 基础路由
app.get('/', (c) => c.text('Hello Hono!'))
app.get('/api/hello', (c) => c.json({ message: 'Hello!' }))

// 路径参数
app.get('/posts/:id', (c) => {
  const id = c.req.param('id')
  const page = c.req.query('page')
  return c.json({ id, page })
})

// POST/DELETE
app.post('/posts', async (c) => {
  const body = await c.req.json()
  return c.json(body, 201)
})
app.delete('/posts/:id', (c) => c.text(`Deleted ${c.req.param('id')}`))

3.2 中间件

复制代码
import { cors } from 'hono/cors'
import { logger } from 'hono/logger'

const app = new Hono()
app.use('*', cors())      // 全局 CORS
app.use('*', logger())    // 全局日志

四、实战:构建 TODO REST API

4.1 项目初始化

复制代码
npm create hono@latest hono-todo-api
# 选择 nodejs 模板
cd hono-todo-api
npm install
npm install @hono/zod-validator

4.2 完整代码

复制代码
import { Hono } from 'hono'
import { cors } from 'hono/cors'
import { logger } from 'hono/logger'
import { z } from 'zod'
import { zValidator } from '@hono/zod-validator'

interface Todo {
  id: number
  title: string
  completed: boolean
  createdAt: string
}

let todos: Todo[] = [
  { id: 1, title: '学习 Hono 基础知识', completed: true, createdAt: new Date().toISOString() },
  { id: 2, title: '理解多运行时概念', completed: false, createdAt: new Date().toISOString() },
  { id: 3, title: '构建一个 REST API', completed: false, createdAt: new Date().toISOString() },
]

let nextId = 4

const createTodoSchema = z.object({
  title: z.string().min(1, '标题不能为空').max(100, '标题不能超过100字'),
})

const updateTodoSchema = z.object({
  title: z.string().min(1).max(100).optional(),
  completed: z.boolean().optional(),
})

const app = new Hono()

app.use('*', cors())
app.use('*', logger())

// GET /todos - 获取所有待办事项
app.get('/todos', (c) => c.json({ todos }))

// GET /todos/:id - 获取单个待办事项
app.get('/todos/:id', (c) => {
  const id = Number(c.req.param('id'))
  const todo = todos.find(t => t.id === id)
  if (!todo) return c.json({ error: '待办事项不存在' }, 404)
  return c.json({ todo })
})

// POST /todos - 创建待办事项
app.post('/todos', zValidator('json', createTodoSchema), async (c) => {
  const { title } = await c.req.json()
  const newTodo: Todo = { id: nextId++, title, completed: false, createdAt: new Date().toISOString() }
  todos.push(newTodo)
  return c.json({ todo: newTodo }, 201)
})

// PUT /todos/:id - 更新待办事项
app.put('/todos/:id', zValidator('json', updateTodoSchema), async (c) => {
  const id = Number(c.req.param('id'))
  const todoIndex = todos.findIndex(t => t.id === id)
  if (todoIndex === -1) return c.json({ error: '待办事项不存在' }, 404)
  const body = await c.req.json()
  todos[todoIndex] = { ...todos[todoIndex], ...body }
  return c.json({ todo: todos[todoIndex] })
})

// DELETE /todos/:id - 删除待办事项
app.delete('/todos/:id', (c) => {
  const id = Number(c.req.param('id'))
  const todoIndex = todos.findIndex(t => t.id === id)
  if (todoIndex === -1) return c.json({ error: '待办事项不存在' }, 404)
  todos.splice(todoIndex, 1)
  return c.json({ message: `已删除 ID 为 ${id} 的待办事项` })
})

app.onError((err, c) => {
  console.error(err)
  return c.json({ error: '服务器内部错误' }, 500)
})

export default app

4.3 运行测试

复制代码
npm run dev
# 访问 http://localhost:3000

4.4 API 结构


五、Hono vs Express 对比

维度 Hono Express
包大小 ~14KB ~572KB(40x)
运行时 Workers/Deno/Bun/Node Node.js 仅
TypeScript 一等公民 外部 @types
异步模型 原生 async/await 回调
JSON 解析 内置 c.req.json() express.json()
CORS 内置 cors() cors

六、结语

Hono 展示了 Web 框架设计的另一种可能------基于 Web 标准,而不是基于运行时。它的设计理念是:框架应该适配运行时,而不是运行时适配框架。

适用场景: Edge API、微服务、Serverless、多运行时兼容项目 学习建议: 有 Express 经验者上手极快,从构建一个 CRUD API 开始,尝试部署到 Cloudflare Workers


七、参考文献

  1. Hono 官方文档

  2. Hono GitHub 仓库

  3. Hono Node.js 适配器

  4. Hono JSON API 指南

  5. Deno + Hono 构建 API

相关推荐
m4Rk_1 小时前
【论文阅读】Agent 记忆机制(47):Nemori——用“预测误差”判断什么经验值得被记住
论文阅读·人工智能·学习·开源·github
TunerT_TQ3 小时前
Microsoft |Playwright CLI 源码静态审阅:从 5 个文件看浏览器自动化工具的工程边界
后端·开源·github
残 风3 小时前
PostgreSQL 存储机制详解
数据库·postgresql·开源·数据库开发
fthux5 小时前
被主流遮住的世界:那些不常见却值得认识的编程语言
人工智能·ai·开源·github
小妖同学学AI5 小时前
开源向量数据库的王者:Milvus 深度解析,专为 AI 应用打造的云原生搜索引擎!
数据库·开源·milvus
william_yangshun6 小时前
【AI Agent 实战】cindy 中文版:开箱即用的开源 AI 代理上手指南
人工智能·开源
冬奇Lab8 小时前
Code Agent 解剖(08):一个任务太复杂,怎么拆给子 agent 做?
人工智能·开源
冬奇Lab8 小时前
开源项目第195期:OpenTelemetry Demo(Astronomy Shop)— 官方出品的分布式系统可观测性实战教材
人工智能·开源·前端工程化
zlinear数据采集卡8 小时前
数据采集卡从入门到精通(38):上位机开发实战——Python/QT/LabVIEW的技术选型与分层架构
python·单片机·嵌入式硬件·qt·fpga开发·开源·labview