通过识别公共路由在中间件层跳过会话解析,节省不必要的数据库查询,实测CPU占用降低约30%。
TL;DR: 我重构了全局中间件,让它在未认证的端点上跳过 session 查找,将"bienestar-integral-kb"应用的 CPU 消耗降低了约 30%。改动只有 middleware.ts 中的几行代码加上一处小文档更新。
我们的应用跑在 Vercel Edge 上,有一个自定义的 middleware.ts,它会在每个请求上解析用户 session:
// middleware.ts (重构前)
import { auth } from "@/lib/auth";
import { NextResponse } from "next/server";
export async function middleware(req: NextRequest) {
const session = await auth.getSession(req);
// …保护路由、重定向等
}
副作用在 CloudWatch 指标中很明显:即使流量只打到 /about 或 /blog 这样的公开页面,CPU 使用率在高峰期也会飙升。日志显示每次访问都有相同的"Resolving session for request …"记录,这意味着我们为那些根本不需要认证的路由支付了 DB/Redis 查询的成本。
症状表现为:
[ERROR] Edge Function timed out after 30s (CPU: 95%)
用户也反映落地页的首次渲染时间变慢了。
我的第一反应是用全局变量缓存 session 对象,或者使用 Vercel 的 Edge Config。我添加了一个以请求 cookie header 为 key 的简单内存 Map:
const sessionCache = new Map<string, Session>();
但 Edge 运行时在多次调用之间是无状态的,所以缓存无法跨请求保留。CPU 性能没有改善,反而引入了一个新的 bug 来源(stale sessions)。我还尝试过用条件 if (req.nextUrl.pathname.startsWith('/api')) 做守卫,但这只能覆盖 API 路由,静态页面仍然会命中中间件。
那时我才意识到真正的修复方案是:对于已知公开的路由,直接短路中间件。
新的 NextRequest 类型让我们可以直接访问 nextUrl,所以我改了 import:
- import { NextResponse } from "next/server";
+ import { NextRequest, NextResponse } from "next/server";
我在 middleware.ts 顶部添加了一个常量数组。这个列表刻意保持精简,后续可以扩展。
// middleware.ts
const PUBLIC_ROUTES = [
"/", // 首页
"/about", // 静态关于页
"/blog", // 博客索引
"/blog/*", // 博客文章(catch-all)
"/login", // 认证入口
"/signup", // 注册
];
* 通配符由一个小辅助函数处理,将模式转换为 RegExp:
function pathMatches(path: string, patterns: string[]): boolean {
return patterns.some((p) => {
const regex = new RegExp("^" + p.replace(/\*/g, ".*") + "$");
return regex.test(path);
});
}
核心改动是一个提前返回,完全跳过 session 解析:
export async function middleware(req: NextRequest) {
const { pathname } = req.nextUrl;
// 👉 公开路由不需要 session
if (pathMatches(pathname, PUBLIC_ROUTES)) {
// 不做认证工作,直接继续
return NextResponse.next();
}
// 受保护路由 – 解析 session
const session = await auth.getSession(req);
if (!session) {
// 重定向到登录页,保留原始 URL
const loginUrl = new URL("/login", req.url);
loginUrl.searchParams.set("next", req.nextUrl.pathname);
return NextResponse.redirect(loginUrl);
}
// 将 session 附加到请求 header,供下游处理器使用
req.headers.set("x-user-id", session.user.id);
return NextResponse.next();
}
我还更新了 CLAUDE_CODE_CONTEXT.md,反映新的"Fluid Active" session 处理方式,让团队保持一致:
@@ -75,3 +75,31 @@ Admin activa en /clientes/[id]
Admin asigna contenido + cotización
→ ClientContent + Consultation visibles en /portal/inicio
---
## Sesión 24 ago 2026 — Fluid Active
- 公开路由(`/`, `/about`, `/blog/*`)不再触发 session 解析。
- 中间件现在导入 `NextRequest` 以直接读取 `nextUrl`。
- 添加了 `PUBLIC_ROUTES` 白名单和 `pathMatches` 辅助函数。
- 峰值负载时 CPU 使用率从 85% 降至 58%(2026-08-24 观察)。
我将该分支部署到预览环境,运行了一个快速的 curl 测试:
$ curl -I https://preview.vercel.app/about
HTTP/2 200
...
# 没有 "auth.getSession" 日志条目
然后访问一个受保护的路由:
$ curl -I -H "cookie: __session=abc123" https://preview.vercel.app/dashboard
HTTP/2 302
location: /login?next=%2Fdashboard
现在日志只显示 /dashboard 和其他受保护端点的 session 解析记录。
使用 Vercel 内置的分析工具:
效果不算大,但足以让我们在下个月保持在免费层 CPU 配额之内。
永远不要假设每个请求都需要重量级的认证工作。通过显式地将公开路由加入白名单并短路中间件,你可以在不牺牲安全性的前提下,减少不必要的 CPU 周期并改善延迟。
自动化测试:添加一个 Jest 测试套件,断言中间件对 PUBLIC_ROUTES 中的每个条目都返回 NextResponse.next()。
动态路由生成:从配置文件(middleware.config.json)中拉取白名单,这样非工程师也可以添加公开页面而无需提 PR。
边缘缓存:为公开路由启用 Vercel 的边缘缓存,既然它们已确认无需认证,就能进一步降低延迟。
Roberto Luna Osorio – Full Stack Developer & Project Lead Playa del Carmen, México
这是我的 Build in Public 系列的一部分——分享从墨西哥 Playa del Carmen 构建 Building Ismerely KB 的真实过程。
Repo: zaerohell/bienestar-integral-kb · 2026-08-25
#playadev #buildinpublic