hono.js 精巧快速的边缘服务框架

Date
Created
Jul 27, 2025 05:12 AM
Descrption
不断进化
Tags
Serverless
学习
架构设计
notion image
💡
还是前端圈有意思,当你在NextJS,NuxtJS,Express,Nest上畅飞的时候,突然又看到了一个更加清凉的框架:hono.js

起源:

Hono 是由日本开发者 Yusuke Wada 在 2021 年 12 月创建的。根据其 GitHub 存储库的介绍,Hono 在日语中意为“火焰”,是“基于 Web 标准构建的一个小巧、简单、速度超快的 Web 框架”。它最初是为 Cloudflare Workers 构建的,但现在可以在“任何 JavaScript 运行时”上运行,包括 Node.js、Deno、Bun 和 Vercel(尽管 Node 支持需要适配器,并且 Node ≥ 18)。
💡
可能也是一些灵感初现,作者开始了side project,觉得性能很好,所以把他做成了一个精巧的框架;
 
但是不得不踩一下国内的互联网环境,哪个公司又能让员工有自己的时间,去研发一个新的框架;

快速的路由匹配:

根据官网的设计哲学,为了达到快速响应,也采用了比较多路由匹配算法,如:
  • RegExpRouter (速度最快)
  • TrieRouter
  • SmartRouter
  • LinearRouter
  • PatternRouter(最轻)
 

支持多种运行时:

  • Cloudflare Workers (workerd)
  • Deno
  • Bun
  • Fastly Compute
  • AWS Lambda
  • Node.js
  • Vercel (edge-light)
 

按需引用功能

Hono 非常小巧,使用最小的预设 hono/tiny,你可以在 12 KB 内写一个 "Hello World" 程序。这是因为它仅使用运行时内置的 Web 标准 API,且功能最小化。相较之下,Express 的打包大小为 579 KB。
notion image
然而,你仍然可以实现许多功能。例如,实现基本身份验证略显麻烦,但 Hono 内置了基本身份验证中间件,你可以这样简单地把基本身份验证应用到 /auth/page 路径:
import { Hono } from 'hono' import { basicAuth } from 'hono/basic-auth' const app = new Hono() app.use( '/auth/*', basicAuth({ username: 'hono', password: 'acoolproject', }) ) app.get('/auth/page', (c) => { return c.text('You are authorized') })
Hono 包包含的内置中间件还允许 Bearer 和 JWT 认证,以及 CORS 的简单配置。这些内置中间件不依赖外部库,但亦可使用许多第三方中间件,这些中间件允许使用外部库,例如使用 Clerk 和 Auth.js 进行身份验证的中间件,以及使用 Zod 和 Valibot 进行验证的中间件。
Hono 还提供了一些内置工具,如 Streaming 助手,对于实现 AI 功能非常有用。这些工具可以按需添加,并且只在添加时增加文件大小。在 Cloudflare Workers 中,Worker 的文件大小有一定限制。保持核心小巧,并通过中间件和助手扩展功能是非常合理的做法。
下面是一些 Hono 具备的中间件和辅助工具,能够大大提升开发效率:
  • Basic Authentication
  • Bearer Authentication
  • Body Limit
  • Cache
  • Compress
  • Context Storage
  • Cookie
  • CORS
  • ETag
  • html
  • JSX
  • JWT Authentication
  • Logger
  • Pretty JSON
  • Secure Headers
  • SSG
  • Streaming
  • GraphQL Server
  • Firebase Authentication
  • Sentry 等
通过引入中间件,Hono 可以实现更为复杂的功能。例如,添加基本身份验证中间件:
import { Hono } from 'hono' import { basicAuth } from 'hono/basic-auth' const app = new Hono() app.use( '/auth/*', basicAuth({ username: 'hono', password: 'acoolproject', }) ) app.get('/auth/page', (c) => { return c.text('You are authorized') })

自定义中间件

通过引入中间件,Hono 可以实现更为复杂的功能。例如,添加基本身份验证中间件:
import { Hono } from 'hono' import { basicAuth } from 'hono/basic-auth' const app = new Hono() app.use( '/auth/*', basicAuth({ username: 'hono', password: 'acoolproject', }) ) app.get('/auth/page', (c) => { return c.text('You are authorized') })

洋葱模型:

Hono 的重要概念是“处理器”和“中间件”。处理器是用户定义的用来接收请求并返回响应的函数。例如,你可以写一个处理器,获取查询参数的值,从数据库中检索数据,并以 JSON 格式返回结果。中间件可以处理来到处理器的请求和处理器返回的响应。你可以将中间件与其他中间件结合起来,构建更大、更复杂的应用程序,可以形象的称之为洋葱结构,“中间件”在 Handler 之前和之后执行,分别处理 Request 和 Response
notion image
app.use(async (c, next) => { const start = performance.now() await next() const end = performance.now() c.res.headers.set('X-Response-Time', `${end - start}`) })
 

默认使用TypeScript:

TypeScript可能已经算大多数开发者的唯一选择了;
 

RPC调用

Hono 拥有强大的类型系统。其中一个功能是 RPC(远程过程调用)。通过 RPC,你可以用 TypeScript 类型表达服务器端 API 规范。当这些类型在客户端作为泛型加载时,每个 API 端点的路径、参数和返回类型都会被推断出来,就像魔法一样。
例如,假设有一个用于创建博客文章的端点。这个端点接受一个 number 类型的 id 和一个 string 类型的 title。使用 Zod(一个支持 TypeScript 推断的验证库),可以定义如下模式:
import { z } from 'zod' const schema = z.object({ id: z.number(), title: z.string() })
然后创建一个处理程序,以 JSON 格式通过 POST 请求接收这个对象,并使用 Zod Validator 检查是否匹配模式。响应将具有一个名为 message 的字符串类型属性
import { zValidator } from '@hono/zod-validator' const app=new Hono().basePath('/v1') // ... const routes= app.post('/posts', zValidator('json', schema), (c) => { const data= c.req.valid('json') return c.json({ message: `${data.id.toString()} is ${data.title}` }) })
这是一个“典型”的 Hono 处理程序,但是你可以通过 typeof 获取的 routes 类型将包含其 Web API 规范的信息。在此例中,它包括创建博客文章的端点——向 /posts 发送 POST 请求会返回一个 JSON 对象。
export type AppType = typeof routes
现在,我们来创建一个客户端。你将先前的 AppType 作为泛型传递给 Hono 客户端对象。
import { hc } from 'hono/client' import { AppType } from '.' const client = hc<AppType>('http://localhost:8787')
设置完毕后,你就可以开始魔法操作了。代码补全工作完美无缺。当你写客户端代码时,不再需要完全了解 API 规范,这也有助于消除错误。

服务端 JSX

Hono 提供了内置的 JSX,这是一种允许你在 JavaScript 中编写类似 HTML 标签的代码的语法。提到 JSX,你可能首先想到 React,这是一个前端 UI 库。然而,Hono 的 JSX 最初是为了仅在服务器端运行而开发的。当首次开始开发 Hono 时,作者在寻找用于渲染 HTML 的模板引擎。大多数模板引擎,如 Handlebars 和 EJS,都在内部使用 eval,而 eval 在 Cloudflare Workers 上不被支持。然后作者想到了使用 JSX。
Hono 的 JSX 独特之处在于它将标签视为一个字符串。因此,以下代码实际上是可行的:
console.log((<h1>Hello!</h1>).toString())
不需要像在 React 中那样调用 renderToString()。如果你想渲染 HTML,只需返回这个字符串即可:
app.get('/', (c) => c.html(<h1>Hello</h1>))
非常有趣的是创建 Suspense —— React 中的一个特性,它允许你在等待异步组件加载时显示一个后备 UI —— 无需任何客户端实现。异步组件在仅服务器实现中运行。
notion image
服务器端 JSX 比你想象的要好玩。你可以用同样的方式为 Hono 的 JSX 复用 React 的 JSX 工具链,包括在编辑器中完成标签的功能,它们将成熟的前端技术带到了服务端。

编写测试

测试非常重要。幸运的是,使用 Hono 你可以轻松编写测试。
例如,让我们为一个接口编写测试。要测试对 / 的 GET 请求返回状态码 200,你可以这样编写:
it('should return 200 response', async () => { const res = await app.request('/') expect(res.status).toBe(200) })
很简单,这种测试的美妙之处在于你不需要启动服务器。Web 标准 API 将服务器层黑箱化。Hono 的内部测试代码有 20000 行,但大多数都像上面那样写成,不需要启动服务器。

走向全栈

notion image
Hono 于2024年2月发布了新的主要版本 4。有三个突出的主要功能:
  • 静态站点生成
  • 客户端组件
  • 基于文件的路由
通过这些功能,我们可以在 Hono 中创建具有用户界面的全栈应用程序。客户端组件的引入支持 JSX 在客户端中工作,我们可以为页面添加交互,静态站点生成允许我们创建博客等,而不必将它们打包成一个 JavaScript 文件。
notion image
Hono 还启动了一个名为 HonoX 的实验项目。这是一个使用 Hono 和 Vite 的元框架,提供基于文件的路由和将客户端组件与服务端生成的 HTML 相结合的机制。更容易创建与 Cloudflare Pages 或 Workers 完美匹配的大型应用程序。
此外,Hono 还计划将其作为现有全栈框架(如 Remix 和 Qwik)的基础服务器运行。与起始于客户端的 React 项目 Next.js 相比,Hono 尝试从服务器端成为全栈框架。