插件
使用运行时插件扩展 Nitro 的运行时行为。
运行时插件会在服务器启动期间执行一次,因此它们适合用于一次性初始化以及注册生命周期钩子。每个插件都会接收 nitroApp 上下文。
插件会从 plugins/ 目录自动注册并按顺序运行。插件也可以是异步的。
import { definePlugin } from "nitro";
export default definePlugin((nitroApp) => {
console.log('Nitro plugin', nitroApp)
})如果你有其他目录中的插件,可以使用 plugins 选项:
import { defineConfig } from "nitro";
export default defineConfig({
plugins: ['my-plugins/hello.ts']
})插件按以下顺序运行:
plugins 选项中列出的顺序运行其中列出的插件。plugins/ 目录自动注册的插件。目录按照 scanDirs 的顺序处理,每个目录中的文件则按路径排序。#异步插件
插件可以返回一个 Promise,例如在服务器开始处理流量前连接数据库:
import { definePlugin } from "nitro";
export default definePlugin(async (nitroApp) => {
const db = await connectToDatabase();
nitroApp.hooks.hook("close", () => db.close());
});异步插件完成后,后续插件才会运行,因此可以依赖该插件所完成的初始化。在所有插件完成之前:
- 传入的请求会暂存,并在初始化完成后处理。
- 以钩子形式分发的平台事件(例如
cloudflare:scheduled或cloudflare:queue)和定时任务也会延后处理。 nitroApp.ready是一个在初始化完成时兑现的 Promise;应用就绪后,其值为undefined。
此机制不依赖顶层 await,因此适用于所有部署目标。所有插件完成后,处理请求不会产生额外开销。
如果插件返回的 Promise 被拒绝,其后的插件将不会运行。错误会传递给 error 钩子并作为未处理的拒绝报告(与同步插件抛出的错误相同);此后请求都会以 500 响应失败。
Warning
不要在异步插件中 await 对应用自身发起的请求(例如 fetch("/api/...")):请求会一直暂存到插件完成,因此永远无法完成。
Note
Cloudflare Workers 等平台不允许在请求上下文之外执行 I/O(例如调用 fetch() 或打开 socket)。插件会在启动时运行,因此在这些平台上应改为延迟建立连接(首次使用时再建立)。
#nitroApp 上下文
插件函数接收一个具有以下属性的 nitroApp 对象:
| 属性 | 类型 | 描述 |
|---|---|---|
hooks | HookableCore | 用于注册生命周期回调的钩子系统。 |
h3 | H3Core | 底层的 H3 应用实例。 |
fetch | (req: Request) => Response | Promise<Response> | 应用的内部 fetch 处理器。 |
captureError | (error: Error, context) => void | 以编程方式将错误捕获到错误钩子管道中。 |
ready | Promise<void> | undefined | 异步插件初始化期间设置的 Promise。 |
Note
H3 会在第一个请求时组合一次中间件链。插件在启动期间添加到 nitroApp.h3["~middleware"] 的中间件会被包含在内,但如果它们位于数组前部,则会在 Nitro 的路由规则之前运行。如果插件在处理第一个请求后修改了该数组,则还必须将 nitroApp.h3["~dispatch"] 和 nitroApp.h3["~composed"] 重置为 undefined,以便重新组合该链。
#Nitro 运行时钩子
使用 Nitro 钩子 在请求生命周期中的特定时间点运行自定义函数。在插件内部使用 nitroApp.hooks.hook() 注册它们:
import { definePlugin } from "nitro";
export default definePlugin((nitroApp) => {
nitroApp.hooks.hook("close", async () => {
// 当 nitro 关闭时运行
});
})#可用的钩子
| 钩子 | 签名 | 描述 |
|---|---|---|
request | (event: HTTPEvent) => void | Promise<void> | 在每个请求开始时调用。 |
response | (res: Response, event: HTTPEvent) => void | Promise<void> | 在响应创建后调用。 |
error | (error: Error, context: { event?: HTTPEvent, tags?: string[] }) => void | 当错误被捕获时调用。 |
close | () => void | 当 Nitro 服务器关闭时调用。 |
Note
NitroRuntimeHooks 接口是可扩展的。部署预设(如 Cloudflare)可以使用平台特定的钩子(如 cloudflare:scheduled 和 cloudflare:email)来扩展它。
#注销钩子
hook() 方法返回一个注销函数,可以调用该函数来移除钩子:
import { definePlugin } from "nitro";
export default definePlugin((nitroApp) => {
const unregister = nitroApp.hooks.hook("request", (event) => {
// ......
});
// 稍后,移除该钩子
unregister();
});#示例
#捕获错误
你可以使用插件来捕获所有应用错误。
import { definePlugin } from "nitro";
export default definePlugin((nitroApp) => {
nitroApp.hooks.hook("error", async (error, { event }) => {
console.error(`${event?.req.url} Application error:`, error)
});
})context 对象包含一个可选的 tags 数组,用于标识错误来源(例如 "request"、"response"、"cache"、"plugin"、"unhandledRejection"、"uncaughtException")。
#以编程方式捕获错误
你可以使用 captureError 手动将错误送入错误钩子管道:
import { definePlugin } from "nitro";
export default definePlugin((nitroApp) => {
nitroApp.captureError(new Error("something went wrong"), {
tags: ["startup"],
});
});#优雅关闭
服务器会优雅地关闭,等待所有使用 event.waitUntil 启动的待处理后台任务。使用 close 钩子清理你自己的资源:
import { definePlugin } from "nitro";
export default definePlugin((nitroApp) => {
nitroApp.hooks.hook("close", async () => {
// 清理资源、关闭连接等。
});
});#请求和响应生命周期
你可以使用插件注册在请求生命周期中运行的钩子:
import { definePlugin } from "nitro";
export default definePlugin((nitroApp) => {
nitroApp.hooks.hook("request", (event) => {
console.log("on request", event.req.url);
});
nitroApp.hooks.hook("response", (res, event) => {
// 修改或检查响应
console.log("on response", res.status);
});
});#修改响应头
import { definePlugin } from "nitro";
export default definePlugin((nitroApp) => {
nitroApp.hooks.hook("response", (res, event) => {
const { pathname } = new URL(event.req.url);
if (pathname.endsWith(".css") || pathname.endsWith(".js")) {
res.headers.append("Vary", "Origin");
}
});
});