mcpField
H
hono

hono

github.com/terminalskills开发19376 次安装3 天前更新
代码仓库

关于 hono

Hono 是用于构建 Web 应用的路由与中间件框架,同一应用可运行于多种 JavaScript 运行时,并提供 JSX、流式响应和类型化 RPC 客户端。

主要功能

  1. 01路由与中间件
  2. 02支持多种运行时
  3. 03类型化 RPC 客户端
  4. 04JSX 渲染与流式响应

适用场景

  1. 01跨运行时构建 API
  2. 02添加身份验证与请求校验
  3. 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 中间件不能直接使用)。

评论

支持 Markdown