Vercel Firewall 编程式限流 SDK 全解vercel/firewall 从实验到稳定的版本演进与实践指南【免费下载链接】vercelDevelop. Preview. Ship.项目地址: https://gitcode.com/gh_mirrors/ve/vercel导读vercel/firewall是 Vercel 开源仓库中用于编程式限流Programmatic Rate Limits的官方 SDK 包它允许开发者直接在 Vercel Functions如 Next.js 的 Route Handlers内通过一行checkRateLimit()调用程序化地查询 Vercel Firewall 中预先配置的限流规则并据此返回 429 状态码。本文以该包 CHANGELOG.md 的版本演进为骨架结合 rate-limit.ts 的完整源码实现与 rate-limit.test.ts 的端到端测试系统讲解checkRateLimit的 API 用法、选项参数、底层请求原理、开发模式行为与工程化演进帮助你在自己的 Vercel 部署中落地可靠、可审计的应用层限流方案。一、版本演进全览一个 SDK 从实验到稳定的完整轨迹CHANGELOG 记录了vercel/firewall从首次发布0.1.0到当前版本 1.2.2 的全部变更其演进脉络清晰展示了 SDK 的核心能力是如何一步步成熟起来的。以下是按时间顺序整理的核心版本里程碑版本变更类型核心内容0.1.0Minor初始发布Initial release限流 SDK 首次亮相0.1.1Patch新增对 Vercel 部署保护绕过deployment protection bypass的支持0.1.3Patch链接到官方文档0.1.4Patch修复 CI 中防火墙测试未被执行的问题0.1.5Patch移除防火墙依赖中的 next 以解决漏洞报告0.1.6Patch将 next 从 14.2.10 升级到 14.2.21安全修复0.1.7Patch修正 README 中指向 SDK 文档的链接1.0.0Major将checkRateLimit标记为稳定stable同时更新包描述1.0.1Patch修复 nextjs 15 中 headers 需要被 await 的问题1.1.0Minor自动处理 vercel auth并支持对所有框架的 magic header 注入1.1.1Patch允许为 Rate Limit 请求设置路径前缀path prefix以支持微前端microfrontends1.1.2Patch引入 syncpack 强制 monorepo 中 types/node 版本一致性升级至 20.11.01.1.3Patch固定 typedoc 插件版本以修复 CI 中不稳定的构建失败1.2.0 / 1.2.1Minor / Patch升级到 TypeScript 5.91.2.2Patch澄清 rate limit key 文档并从错误信息中移除x-real-ip实现细节从版本线可以看出三个关键信号0.1.x 阶段是功能补齐期绕过支持、文档、测试、安全修复1.0.0 是分水岭checkRateLimit正式从实验性 API 转为稳定 API1.1.x 之后则聚焦在框架兼容性headers await、微前端路径前缀、auth 自动化与工程基建syncpack、TypeScript 5.9、typedoc 插件固定上。在 1.0.0 之前SDK 只导出unstable_checkRateLimit实验别名1.0.0 之后checkRateLimit成为主导出名。这一点在 src/rate-limit.ts 末尾可以得到印证——源码通过export { checkRateLimit as unstable_checkRateLimit }保留了向后兼容的旧名称。二、快速上手在 Vercel Functions 中使用 checkRateLimitvercel/firewall的 README 与 API 文档给出了最简洁的用法。在 Next.js Route Handler 中你可以这样为某个接口加上限流保护import { checkRateLimit } from vercel/firewall; export async function POST() { const { rateLimited } await checkRateLimit(my-rate-limit-id); if (rateLimited) { return new Response(, { status: 429, }); } // Implement logic guarded by rate limit }核心调用逻辑只有三步传入rateLimitId这个 ID 必须与你在 Vercel Firewall 控制台中配置的、条件为vercel/firewall的限流规则 ID 完全一致SDK 通过该 ID 匹配对应规则读取返回值checkRateLimit返回一个 Promise解析为{ rateLimited: boolean; error?: not-found | blocked }根据结果放行或拒绝当rateLimited为true时返回 HTTP 429Too Many Requests否则继续执行业务逻辑。完整的函数签名定义于 rate-limit.ts为checkRateLimit( rateLimitId: string, options?: { firewallHostForDevelopment?: string; rateLimitKey?: string; headers?: Headers | Recordstring, string | Recordstring, string | string[]; request?: Request; } ): Promise{ rateLimited: boolean; error?: not-found | blocked }需要特别注意的是当前包版本1.2.2见 package.json要求 Node.js 20并且由于内部依赖 Web 标准fetch、Headers与crypto.subtle它天然面向 Vercel Functions / Edge Runtime 这类现代运行时设计。三、选项参数详解四个可选字段的用途与优先级options对象中的四个字段在 checkRateLimit.md 中有官方说明结合源码实现可以进一步确认它们各自的作用与优先级3.1rateLimitKey被限流的实体标识rateLimitKey?: string; // 被限流的实体默认取客户端 IP这是限流计数的主键决定谁被计数。默认情况下SDK 会从请求头的x-real-ip中提取客户端 IP 作为 key当未提供rateLimitKey且请求头中也没有x-real-ip时源码会直接抛出错误Could not determine rate limit key. rateLimitKey option is not provided and the client IP is not available.rate-limit.ts。在 1.2.2 版本中CHANGELOG 明确澄清 rate limit key 文档并从错误信息中移除x-real-ip实现细节即该 key 的提取细节不再暴露在错误信息中但默认回退到客户端 IP 的行为保持一致。对于需要按用户 ID、API Key 或设备维度限流的场景显式传入rateLimitKey是最可靠的方式。3.2headers/request请求上下文的来源headers?: Headers | Recordstring, string | Recordstring, string | string[]; request?: Request; // 当前请求对象可选SDK 需要一个请求上下文来读取 host、客户端 IP 与转发相关头。源码中的优先级rate-limit.ts为优先使用显式传入的options.headers否则使用options.request.headersRequest对象自动携带若两者都没有则尝试从Symbol.for(vercel/request-context)全局符号中读取请求上下文getContext()函数仍无结果则抛出headers or request options are required错误。值得注意的是headers参数既支持原生Headers实例也支持普通的键值对象包括值为字符串数组的变体源码会自动通过new Headers(...)完成归一化。3.3firewallHostForDevelopment开发模式的宿主指定firewallHostForDevelopment?: string; // 限流规则所定义的主机名由于本地开发环境没有 Vercel 平台的自动注入SDK 在NODE_ENV ! production时会检查该选项。若未提供会输出警告Provide the firewallHostForDevelopment option to support rate-limiting in development mode并直接返回rateLimited: false放行测试中则使用特殊值ignore-for-testing表示沿用请求头中的真实 host详见下文开发与测试模式章节。3.4 自动上下文获取零配置接入所有框架getContext()是 1.1.0自动处理 vercel auth 并支持对所有框架的 magic header 注入这一能力的技术基础。源码通过Symbol.for(vercel/request-context)这个全局注册表符号读取运行时注入的请求上下文rate-limit.tsconst SYMBOL_FOR_REQ_CONTEXT Symbol.for(vercel/request-context); function getContext(): Context { const fromSymbol globalThis; return fromSymbol[SYMBOL_FOR_REQ_CONTEXT]?.get?.() ?? {}; }这意味着当运行平台或框架适配层在全局注册了请求上下文后开发者无需手动传headers/request也能完成限流检查这正是对所有框架的 magic header 注入得以实现的底层机制。四、底层原理一次 checkRateLimit 调用实际发生了什么从源码实现看checkRateLimit的本质是向 Vercel Firewall 暴露的限流查询端点发起一次内部 HTTP 请求由防火墙侧完成计数与判定。完整流程如下4.1 构造查询 URLlet pathPrefix process.env.PUBLIC_VERCEL_FIREWALL_PATH_PREFIX || process.env.NEXT_PUBLIC_VERCEL_FIREWALL_PATH_PREFIX || ; if (pathPrefix !pathPrefix.startsWith(/)) { pathPrefix /${pathPrefix}; } const url https://${firewallHost}${pathPrefix}/.well-known/vercel/rate-limit-api/${encodeURIComponent(rateLimitId)};URL 结构为https://hostpathPrefix/.well-known/vercel/rate-limit-api/rateLimitId其中firewallHost在开发模式下取自firewallHostForDevelopment选项生产环境则取请求头的host。rateLimitId会经过encodeURIComponent编码后拼入路径。4.2 混淆限流 key防止计数被绕过为了防止攻击者通过伪造rateLimitKey或 IP 来绕过限流SDK 会先对 key 做一次加盐哈希rate-limit.tsfullRateLimitKey ${fullRateLimitKey}-${await hashString( fullRateLimitKey rateLimitId (process.env.VERCEL_AUTOMATION_BYPASS_SECRET || ) (process.env.RATE_LIMIT_SECRET || ) )};hashString使用 Web Crypto 的crypto.subtle.digest(SHA-256, ...)计算十六进制摘要rate-limit.ts。参与哈希的盐包括rateLimitId与两个环境变量其中VERCEL_AUTOMATION_BYPASS_SECRET正是 0.1.1部署保护绕过支持的落点。4.3 构造并发送请求头查询请求使用 GET 方法并携带一组专用头rate-limit.tsconst rateLimitHeaders new Headers({ x-vercel-rate-limit-api: rateLimitId, x-vercel-rate-limit-key: fullRateLimitKey, user-agent: Bot/Vercel Rate Limit Checker, x-forwarded-for: requestHeaders.get(x-forwarded-for) || , x-real-ip: requestHeaders.get(x-real-ip) || , x-vercel-protection-bypass: process.env.VERCEL_AUTOMATION_BYPASS_SECRET || , });此外还有两个值得关注的细节Cookie 转发如果请求中包含_vercel_jwt认证 Cookie会被解析并单独转发parseCookies函数按;拆分 cookie 对用于让防火墙感知已登录用户其他 Cookie 一律不转发rate-limit.ts全量头回传原始请求的每一个头都会以x-rr-原头名的形式追加到查询请求中rateLimitHeaders.append(\x-rr-${key}, value)保证防火墙侧可以基于任意请求属性做判定。4.4 解析响应状态码请求使用redirect: manual发起然后根据 HTTP 状态码映射结果rate-limit.ts状态码返回值含义204{ rateLimited: false }未触发限流正常放行429{ rateLimited: true }触发限流应返回 429403{ rateLimited: true, error: blocked }被防火墙规则直接拦截如黑名单/挑战失败404{ rateLimited: false, error: not-found }未找到对应 rate limit ID并输出 warn 日志其他抛出Unexpected rate-limit API response status ...平台异常建议按失败放行策略处理这套按状态码精确映射的设计让调用方可以用最少的代码同时处理限流、拦截与配置错误三种情况。五、开发与测试模式本地限流验证的两种姿势NODE_ENV在 SDK 行为中扮演关键角色。源码中一共有三处针对非生产环境的特殊处理未传firewallHostForDevelopment输出警告并直接返回{ rateLimited: false }放行保证本地开发不被限流打断传了firewallHostForDevelopment用它替换请求头中的host作为查询目标让你可以在本地指向一个真实承载限流规则的部署进行联调特殊值ignore-for-testing此时沿用请求头中的host字段用于单元测试与端到端测试场景。这一行为在 rate-limit.test.ts 中被大量验证。测试用例覆盖了限流计数语义同一 key 连续两次请求返回rateLimited: false第三次起返回true换一个 key 则重新计数对应规则 2 requests 后触发限流key 来源的三种形态显式rateLimitKey、从Headers中的x-real-ip提取、从普通对象形态的 headers 提取、以及从Request对象提取头转发正确性user-agent固定为Bot/Vercel Rate Limit Checker自定义头会以x-rr-*前缀透传如x-rr-random-headerCookie 选择性转发存在_vercel_jwt时仅转发该 Cookie其他 Cookie如session不转发全局上下文兜底在globalThis上设置vercel/request-context后即使不传headers/request也能取到请求头路径前缀设置NEXT_PUBLIC_VERCEL_FIREWALL_PATH_PREFIXtest-prefix后查询 URL 变为https://host/test-prefix/.well-known/vercel/rate-limit-api/test-rule1。测试同时验证了src源码入口、dist构建产物入口以及unstable_checkRateLimit旧别名三种导入方式的等价性rate-limit.test.ts确保构建与重构不会破坏兼容性。六、微前端场景路径前缀的配置与含义1.1.1 引入的路径前缀功能是为解决微前端microfrontends部署下的一个现实问题当多个前端应用共享同一个域名或部署环境时.well-known限流端点可能被路由到错误的子应用导致防火墙查询请求 404。解决方案是通过环境变量指定路径前缀# 二选一源码中 PUBLIC_VERCEL_FIREWALL_PATH_PREFIX 优先 PUBLIC_VERCEL_FIREWALL_PATH_PREFIXmy-app # 或面向 Next.js 客户端环境的版本 NEXT_PUBLIC_VERCEL_FIREWALL_PATH_PREFIXmy-app源码会读取这两个环境变量前者优先并自动补全前导/rate-limit.ts最终请求形如https://host/my-app/.well-known/vercel/rate-limit-api/rateLimitIdNEXT_PUBLIC_前缀的存在意味着 Next.js 应用中该值可以在客户端与服务器端共享同一配置而PUBLIC_变体则适用于其他框架或纯 Node 运行时。七、工程化与发布实践CHANGELOG 之外的仓库佐证CHANGELOG 中 1.1.2、1.1.3、1.2.0 等版本记录的并不仅是功能变更还揭示了该包在 monorepo 中的工程质量要求依赖版本一致性1.1.2引入 syncpack 强制整个 monorepo 的types/node版本一致并升级到 20.11.0避免不同包之间类型定义漂移导致的兼容性问题——package.json 中types/node: 20.11.0正是这一治理的结果文档构建稳定性1.1.3固定typedoc-plugin-markdown3.15.2与typedoc-plugin-mdn-links3.0.3修复 pnpm hoisting 导致 typedoc 插件版本不确定、从而引发 CI 偶发失败的隐患。当前仓库 typedoc.json 中已升级为typedoc-plugin-markdown与typedoc-plugin-mdn-links组合package.json 中对应版本为typedoc 0.28.19/typedoc-plugin-markdown 4.11.0/typedoc-plugin-mdn-links 5.1.1且脚本build在生成文档后会自动执行prettier --write docs/**/*.md统一格式类型升级1.2.0 / 1.2.1升级到 TypeScript 5.9保持与 tsconfig.base.json 及仓库整体工具链同步。包的发布配置package.json也值得注意exports字段仅暴露.入口types 指向dist/index.d.tsdefault 指向dist/index.jsfiles仅包含dist目录license为 Apache-2.0publishConfig.access为public说明这是一个面向 npm 公开发布、体积受控的独立运行时包。其公开 API 面极小——src/index.ts 只有一行export * from ./rate-limitdocs/README.md 中列出的公开符号也仅有checkRateLimit与unstable_checkRateLimit别名。八、最佳实践小结综合 CHANGELOG 演进、源码实现与测试用例可以总结出使用vercel/firewall的几个实操要点先配置后调用rateLimitId必须与 Vercel Firewall 控制台中vercel/firewall条件规则一致否则会收到error: not-found与警告日志生产环境无需手动传 host平台会自动注入请求上下文与 host本地开发则必须提供firewallHostForDevelopment否则默认放行按实体维度选择 key按 IP 限流可用默认行为按用户/API Key 限流请显式传入rateLimitKey并注意它会被加盐哈希后发送不会被明文透传处理好三类响应429 直接返回 429error: blocked表示被防火墙拦截error: not-found表示配置缺失业务上建议放行并告警微前端记得配置路径前缀通过PUBLIC_VERCEL_FIREWALL_PATH_PREFIX或NEXT_PUBLIC_VERCEL_FIREWALL_PATH_PREFIX指定前缀避免跨子应用路由冲突关注运行时要求当前版本要求 Node.js 20内部依赖 Web 标准fetch/Headers/crypto.subtle请确保目标运行时满足条件。通过 CHANGELOG 我们可以完整看到这个 SDK 的成熟路径——从实验性 API 到 1.0.0 稳定再到微前端支持与跨框架自动上下文注入——而 rate-limit.ts 的实现则为编程式限流这一模式提供了可读、可测试、可审计的参考范本。对于希望在 Vercel 平台上实现应用层限流的团队vercel/firewall是当前仓库中开箱即用的官方方案。【免费下载链接】vercelDevelop. Preview. Ship.项目地址: https://gitcode.com/gh_mirrors/ve/vercel创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
