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

相关推荐
海绵宝宝转agent4 小时前
MySql高频面试八股开源笔记总结
mysql·面试·开源
niyongsheng8 小时前
后端零改动,给若依换一套现代化前端
vue.js·开源·node.js
EasyBr指纹浏览器8 小时前
抖音创作者数据导出:怎样留下可比较的日报?
数据分析·开源·抖音·数据导出
Sweet锦9 小时前
不调 Python,不装向量库:我用纯 Java 写了一套以图搜图引擎
java·人工智能·开源·图搜索
网络毒刘9 小时前
开源 AI 编程助手横向对比(Cursor / Continue / Aider):能力边界与 AtomGit 落地建议
人工智能·开源
盘古开天166610 小时前
windows鱼塘可交互鱼群动态桌面资源
人工智能·chatgpt·开源
枫叶丹411 小时前
从一次推理请求出发:模型、显存、网络与服务系统如何共同决定性能
网络·人工智能·chatgpt·开源·agent·codex
deepseek2312 小时前
Kolibri 拆解:计算像 3.5B、显存要 78GB 的德国主权模型,把合规做进六个架构决策
开源·大模型·moe·aiagent·ai架构
EasyBr指纹浏览器12 小时前
抖音账号诊断:公开作品样本能说明什么?
数据分析·开源·内容运营·抖音