简介
H3 是 Nuxt 3 和 Nitro 的核心 HTTP 框架,提供了极简且高效的中间件机制。中间件(Middleware)是指在请求到达最终处理函数(Handler)之前,依次执行的一系列函数。它们可以用于处理认证、日志、错误处理、请求解析等通用逻辑。
特点
- 极简 API:中间件的编写和使用非常简单,易于上手。
- 高性能:基于现代 Node.js 特性,性能优异。
- 灵活组合:支持多个中间件串联,按顺序依次执行。
- 类型安全:TypeScript 支持良好,开发体验佳。
- 与 Nuxt/Nitro 深度集成:可无缝用于 Nuxt 3、Nitro 项目。
示例
基础示例
定义中间件
// middleware/logger.js
export default (req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
next();
};
在 H3 应用中注册:
import { H3 } from "h3";
import logger from "./middleware/logger";
const app = new H3();
app.use(logger);
app.use("/hello", (req, res) => {
res.end("Hello World");
});
serve(app, { port: 3000 });
条件使用:可以根据路径、方法等条件灵活应用
app.use("/api", apiMiddleware);
app.use("/admin", adminAuthMiddleware);
常见应用场景
- 认证与权限校验
- 日志记录
- 请求体解析
- 错误统一处理
- CORS 处理
参考链接
中间件
响应时间
app.use(async (event, next) => {
const start = Date.now();
await next();
const end = Date.now();
console.log(`Response time: ${end - start}ms`);
});
统一响应头
app.use((event, next) => {
event.res.headers.set("Content-Type", "application/json; charset=utf-8");
return next();
});
访问统计
app.use(async (event, next) => {
const url = event.req.url;
const statsFile = "logs/stats.json";
let stats = {};
try {
stats = JSON.parse(await readFile(statsFile, "utf-8"));
} catch {}
stats[url] = (stats[url] || 0) + 1;
await writeFile(statsFile, JSON.stringify(stats, null, 2));
return next();
});
跨域(CORS)
app.use((event, next) => {
event.res.headers.set("Content-Type", "application/json; charset=utf-8");
event.res.headers.set("Access-Control-Allow-Origin", "*");
event.res.headers.set(
"Access-Control-Allow-Methods",
"GET,POST,PUT,DELETE,OPTIONS"
);
event.res.headers.set(
"Access-Control-Allow-Headers",
"Content-Type,Authorization"
);
// 预检请求直接返回
if (event.req.method === "OPTIONS") {
return "";
}
return next();
});
禁止某些 UA 访问
app.use((event, next) => {
const ua = event.req.headers.get("user-agent") || "";
if (ua.includes("curl") || ua.includes("python")) {
event.res.statusCode = 403;
return { code: 403, message: "禁止访问" };
}
return next();
});
禁用指定 IP 访问
const blacklist = ["1.2.3.4", "5.6.7.8"];
app.use((event, next) => {
const ip =
event.req.headers.get("x-forwarded-for") || event.req.socket.remoteAddress;
if (blacklist.includes(ip)) {
event.res.statusCode = 403;
return { code: 403, message: "IP被禁止访问" };
}
return next();
});
国际化(i18n)
const messages = {
zh: { welcome: "欢迎" },
en: { welcome: "Welcome" },
};
app.use((event, next) => {
const lang = event.req.headers
.get("accept-language")
?.split(",")[0]
.toLowerCase()
.startsWith("zh")
? "zh"
: "en";
event.t = (key) => messages[lang][key] || key;
return next();
});
// 用法:handler里 return { msg: event.t("welcome") }
接口缓存
const cache = new Map();
app.use(async (event, next) => {
if (event.req.method === "GET") {
const key = event.req.url;
if (cache.has(key)) {
return cache.get(key);
}
const result = await next();
cache.set(key, result);
setTimeout(() => cache.delete(key), 10 * 1000); // 缓存10秒
return result;
}
return next();
});
原文链接:https://code.ifrontend.net/archives/741,转载请注明出处。
评论0