H3 1.8 - 迈向 Web 边缘

发布于
-
分类
作者

H3 是一个多功能的 H(TTP) 框架,采用 TypeScript 编写,目前为 NitroNuxt 提供支持。

近两年前,我们创建了 H3,旨在成为 Nuxt 3 最轻量的 HTTP 框架,确保与 Node.js 兼容并提供优雅的开发体验。它还致力于拥有未来主义的设计,能够适应 Edge 和 Web Worker 运行时,这在当时是一个相对较新的概念。

同期,我们还开发了 unjs/unenv,这是一个轻量层,无需 Node.js 即可让 Edge 兼容运行时使用 Node.js 库和 HTTP 中间件。这项创新在帮助我们利用 NPM 和 Node.js 生态系统的强大功能方面发挥了关键作用,而无需从头开始为 Web 兼容性构建一切。H3 和 unenv 的协同组合最终使 Nitro 成为完全兼容 Edge 运行时的开创性 Web 框架之一。

此次最新发布使 H3 更接近于开箱即用地提供原生 Web API 兼容性。

🚀 此版本已立即向包括 NitroNuxt 3 在内的所有生态系统软件包开放。请记住刷新您的 lockfilenode_modules 以接收更新。

Web 和 Plain 适配器

我们引入了一个新的内置适配器,它具有与 fetch 兼容的签名,以 Request 作为输入,以 Response 作为返回值。

这意味着您现在可以将 H3 应用程序无缝部署到诸如 Cloudflare WorkersDeno DeployBunLagon 等运行时上。

有关实际示例和演示,请查看 h3-on-edge 仓库。

// import { createApp, eventHandler, toWebHandler } from 'h3'
import { createApp, eventHandler, toWebHandler } from 'https://esm.sh/[email protected]'

const app = createApp()

app.use(
  '/',
  eventHandler(event => 'H3 works on edge!'),
)

const webHandler = toWebHandler(app) // (Request) => Promise<Response>

除了 Web 处理程序,我们还引入了一种新的 plain 适配器格式,使用 toPlainHandler(app) 语法。这有助于 H3 与任何使用 plain 输入和响应对象的无服务器平台无缝集成。

所有这些都得益于新流式传输功能的实现以及 unjs/unenv(它提供了轻量级的 Node.js 兼容层)。此前,这种级别的集成只能通过 Nitro presets 来实现。

此外,我们还引入了一系列新的 Web 助手函数

  • toWebRequest(event):将 H3 事件对象转换为 Web Request
  • getRequestWebStream(event):从当前 H3 事件请求中获取可读流。
  • fromPlainHandler(plainHandler):将 plain 对象处理程序转换为 H3 兼容的事件处理程序。
  • fromWebHandler(webHandler):将 Web Request/Response 处理程序转换为 H3 兼容的事件处理程序。

Web Streams 支持

H3 现在支持原生 Readable Stream 响应。这本身就带来了与 Vercel/AI 等库的兼容性,这些库依赖于流式响应(demo)。

利用此功能非常简单——只需从您的事件处理程序返回一个 Readable StreamResponse 对象。

export default defineEventHandler((event) => {
  setResponseHeader(event, 'Content-Type', 'text/html')
  const encoder = new TextEncoder()
  const stream = new ReadableStream({
    async start(controller) {
      for (const token of 'Streaming is so cool with H3!'.split(' ')) {
        controller.enqueue(encoder.encode(token))
        await new Promise((resolve) => {
          setTimeout(resolve, 300)
        })
      }
    },
  })
  return stream
})

对于更高级的场景,您可以选择使用 sendStream(event, stream)sendWebResponse(event, stream) 工具函数,而不是直接返回流。

对象语法事件处理程序

H3 引入了使用对象语法定义事件处理程序的支持。通过这种方法,您可以定义在每个处理程序运行之前或之后运行的钩子,例如身份验证或压缩中间件。

const auth = defineRequestMiddleware((event) => {
  event.context.auth = { name: 'admin' }
})

const compression = defineResponseMiddleware((event) => {
  // Example: https://stackblitz.com/edit/github-mb6bz3
})

export default eventHandler({
  onRequest: [auth],
  onBeforeResponse: [compression],
  async handler(event) {
    return `Hello ${event.context.auth?.name || 'Guest'}`
  },
})

类型化事件处理程序请求

H3 现在支持使用新的泛型类型支持来定义事件类型。

当您定义类型时,请求工具将感知事件输入类型。此增强功能还使我们能够提高上游框架(如 NitroNuxt)中 $fetch 处理程序的类型安全性。

export default eventHandler<{ body: { name: string }, query: { id: string } }>(
  async (event) => {
    const query = getQuery(event) // Query is typed as { id: string }
    const body = await readBody(event) // Body is typed as { name: string }
  },
)

运行时 + 类型安全的请求工具

两个新的工具函数 getValidatedQuery(event, validator)readValidatedBody(event, validator) 方便与 zod 等模式验证器集成,以实现运行时和类型安全。

import { z } from 'zod'

const userSchema = z.object({
  name: z.string().default('Guest'),
  email: z.string().email(),
})

export default defineEventHandler(async (event) => {
  const result = await readValidatedBody(event, body => userSchema.safeParse(body)) // or `.parse` to directly throw an error

  if (!result.success)
    throw result.error.issues

  // User object is validated and typed!
  return result.data
})

额外工具

我们还引入了其他几个工具,以进一步增强 Web 应用程序开发体验

  • getRequestIP(event, { xForwardedFor? }):获取传入请求的 IP。
  • readFormData(event):将请求体读取为 FormData
  • clearResponseHeaders(event):清除所有响应头。
  • removeResponseHeader(event, name):移除特定的响应头。
  • serveStatic(event, options):平台无关的静态资产服务器。请查看 listhen 源码,了解在 Node.js 中使用的示例。

借助 HMR 实现轻松的 TypeScript 开发

我们还发布了 unjs/listhen 的更新版本,它可以与 H3 应用程序无缝集成。

您只需创建一个 index.ts 文件

import { createApp, eventHandler } from 'h3'

export const app = createApp()

app.use('/', () => 'Hello world!')

运行 npx listhen@latest -w ./index.ts 以启动一个支持 TypeScript、热模块替换 (HMR) 和静态资产服务器的开发服务器。

在线演练场

Screenshot of listhen

完整变更日志

有关完整的变更列表,请参阅 发行说明