关于 hono
Hono 是用于构建 Web 应用的路由与中间件框架,同一应用可运行于多种 JavaScript 运行时,并提供 JSX、流式响应和类型化 RPC 客户端。
主要功能
- 01路由与中间件
- 02支持多种运行时
- 03类型化 RPC 客户端
- 04JSX 渲染与流式响应
适用场景
- 01跨运行时构建 API
- 02添加身份验证与请求校验
- 03创建类型化 API 客户端
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ terminalskills/ skills --skill hono安装后在 Claude Code 中输入/hono确认已加载。
附带文件_scores.json
详细介绍
Hono — 极速 Web 框架
概述
Hono(hono 4.x,已根据 4.13 进行验证)是一个仅基于 Request/Response 构建的路由器和中间件,因此同一个应用对象可以运行在 Workers、Bun、Deno、Node.js、Lambda 和 Vercel 上。核心包自带中间件(hono/cors、hono/jwt、hono/logger、hono/csrf、hono/secure-headers、hono/body-limit、hono/compress、hono/etag、hono/timeout、hono/request-id 等)、JSX 渲染器(hono/jsx)和类型化 RPC 客户端(hono/client)。验证器等第三方中间件位于 @hono/* 包中。它没有内置的速率限制器或 ORM。
说明
创建项目
npm create hono@latest orders-api
# pick a template: cloudflare-workers, nodejs, bun, deno, aws-lambda, vercel, ...
cd orders-api && npm install && npm run dev
对于现有的 Node.js 项目,安装 hono 和 @hono/node-server,并使用 serve({ fetch: app.fetch, port: 3000, hostname: "127.0.0.1" }) 启动应用。在 Workers、Bun 和 Deno 上,则改为 export default app。
带验证和 JWT 的 API 路由
单独安装验证器:npm install @hono/zod-validator zod。
import { Hono } from "hono";
import { cors } from "hono/cors";
import { logger } from "hono/logger";
import { jwt, sign } from "hono/jwt";
import { zValidator } from "@hono/zod-validator";
import { z } from "zod";
type Variables = { jwtPayload: { sub: string } };
const app = new Hono<{ Variables: Variables }>();
app.use(logger());
app.use("/api/*", cors({ origin: ["https://brightcart.io"], credentials: true }));
// `alg` is required: the middleware throws without it
app.use("/api/protected/*", jwt({ secret: process.env.JWT_SECRET!, alg: "HS256" }));
const createUser = z.object({
name: z.string().min(1),
email: z.email(), // zod 4; on zod 3 use z.string().email()
role: z.enum(["user", "admin"]).default("user"),
});
const routes = app
.post("/api/users", zValidator("json", createUser), (c) => {
const body = c.req.valid("json"); // { name: string; email: string; role: "user" | "admin" }
return c.json(body, 201);
})
.get("/api/protected/me", (c) => c.json({ userId: c.get("jwtPayload").sub }));
export type AppType = typeof routes;
export default app;
不符合架构的请求体会自动得到 400 JSON 响应。按上述方式链式注册路由,这样 typeof routes 才会包含所有路由类型并传递给客户端;使用独立的 app.get(...) 语句注册的路由不包含在类型中。使用 await sign({ sub: user.id, exp: Math.floor(Date.now() / 1000) + 3600 }, secret, "HS256") 签发令牌(sign 是异步函数,算法作为第三个参数传入)。
使用 c.req.param("id") 读取路径参数,使用 c.req.query("page") 读取查询参数,使用 c.req.header("x-request-id") 读取请求头。通过挂载子应用对路由分组:app.route("/api/orders", ordersApp)。
错误
import { HTTPException } from "hono/http-exception";
app.notFound((c) => c.json({ error: "Not found" }, 404));
app.onError((err, c) => {
// JWT, bearer-auth and other middleware throw HTTPException: keep its status
if (err instanceof HTTPException) return err.getResponse();
console.error(err);
return c.json({ error: "Internal server error" }, 500);
});
如果没有 HTTPException 分支,缺少令牌时会返回 500,而不是 401。
RPC 客户端
import { hc } from "hono/client";
import type { AppType } from "./server";
const client = hc<AppType>("https://api.brightcart.io");
const res = await client.api.users.$post({ json: { name: "Alice", email: "[email protected]" } });
if (res.ok) console.log(await res.json());
客户端代码中只从服务器文件导入 import type。动态路径段的调用方式为 client.api.users[":id"].$get({ param: { id: "42" } })。
JSX、HTML 和流式传输
JSX 需要在 tsconfig.json 中设置 "jsx": "react-jsx" 和 "jsxImportSource": "hono/jsx",并且文件必须使用 .tsx 扩展名(Workers 模板已预先设置)。
import { getRuntimeKey } from "hono/adapter";
import { streamText } from "hono/streaming";
app.get("/", (c) =>
c.html(
<html>
<body>
<h1>Order dashboard</h1>
<p>Runtime: {getRuntimeKey()}</p>
</body>
</html>
)
);
app.get("/stream", (c) =>
streamText(c, async (stream) => {
for (const word of ["Preparing", "your", "report"]) {
await stream.write(word + " ");
await stream.sleep(100);
}
})
);
streamText、stream 和 streamSSE 来自 hono/streaming;旧版的 c.streamText() 上下文方法在 4.x 中已不存在。使用 hono/adapter 中的 getRuntimeKey() 检测运行时("node"、"workerd"、"bun"、"deno")。
示例
示例 1:“为我的 Hono API 添加受保护的端点”
请求:“只有已登录用户才能调用 GET /api/protected/me。”
步骤:如上所示,在 /api/protected/* 上添加 jwt({ secret: process.env.JWT_SECRET!, alg: "HS256" }),然后读取 c.get("jwtPayload")。不带请求头的请求会返回 401(使用上面的 onError 分支);带有效 Authorization: Bearer <token> 的请求会返回 {"userId":"u1"}。
示例 2:“验证注册请求体”
请求:“拒绝姓名为空的注册请求。”
步骤:为路由附加 zValidator("json", createUser)。POST /api/users 携带 {"name":"Alice","email":"[email protected]"} 时,会返回 201,默认值会填入 "role":"user";携带 {"name":""} 时,会返回 400 和 Zod 问题详情。
指南
- 始终在
jwt()中设置alg,并将密钥保存在环境变量中(在 Workers 上,通过包装中间件从c.env.JWT_SECRET读取)。 - 将
@hono/zod-validator固定到与 Zod 主版本匹配的版本;主版本不匹配会导致类型错误。 - 中间件顺序很重要:必须在需要覆盖的路由之前注册
cors(),而处理器一旦返回Response,调用链就会结束。 - 面向浏览器的应用应添加
body-limit、secure-headers和csrf;速率限制需要第三方包或平台功能(Cloudflare rules)。 - 本地 Node 服务器应绑定到
127.0.0.1,除非你确实要将其公开。 - 不要将 Hono 用于依赖 Node 专属框架插件生态的应用(Express 中间件不能直接使用)。