ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Cloudflare Snippets 边缘逻辑实战指南:轻量 JavaScript 规则引擎的配置、API 与实战模式

Cloudflare Snippets 边缘逻辑实战指南:轻量 JavaScript 规则引擎的配置、API 与实战模式 Cloudflare Snippets 边缘逻辑实战指南轻量 JavaScript 规则引擎的配置、API 与实战模式【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills本文是 Cloudflare Deploy Skill 中 Snippets 参考文档 的深度解读围绕 Cloudflare Snippets 这一轻量级边缘逻辑平台展开它依托 Ruleset Engine用一段 JavaScript 即可在请求/响应路径上完成头部注入、地理路由、A/B 测试等改造。读完本文你将掌握 Snippets 与 Workers 的选型边界、四种部署方式Dashboard / REST API / Terraform / Pulumi、Ruleset Engine 过滤表达式语法、核心 API 用法以及 7 个可直接落地的生产级代码模式与常见错误排查清单。什么是 Cloudflare SnippetsCloudflare Snippets 是一种基于 JavaScript 的轻量级边缘逻辑平台用于在 HTTP 请求和响应通过 Cloudflare 网络时对其进行修改。它与 Workers 的关键区别在于Snippets 是作为Ruleset Engine 的一部分运行的并已在Pro、Business、Enterprise 付费套餐中免费包含无需额外付费。根据参考文档Snippets 的核心特征如下特征说明执行时间每个请求 5ms CPU 上限体积限制每个 Snippet 32KB运行时V8 isolateWorkers API 的子集子请求按套餐 25 次fetch调用成本已包含在 Pro / Business / Enterprise 套餐中从本仓库 SKILL.md 的决策树可以看到Snippets 被归类在运行代码路径下的轻量级边缘逻辑修改 HTTP→ snippets/分支与 Workers无服务器函数、Pages全栈 Web 应用等重型方案形成互补是纯请求/响应改造场景的推荐选项。Snippets vs Workers 决策矩阵Snippets 与 Workers 能力重叠但定位不同参考文档给出了完整的决策矩阵因素选 Snippets 如果……选 Workers 如果……复杂度简单的请求/响应修改复杂业务逻辑、路由、中间件执行时间5ms 以内足够需要 5ms 或可变时间子请求25 次 fetch 调用足够需要 5 次子请求或复杂编排代码体积32KB 以内足够需要 32KB 或 npm 依赖成本想要零额外成本能接受 $5/月 用量费用API需要基础 fetch、headers、URL需要 KV、D1、R2、Durable Objects、cron 触发器部署需要基于规则的触发需要自定义路由逻辑参考文档给出的经验法则是用 Snippets 做修改用 Workers 做应用Use Snippets for modifications, Workers for applications。当需求超出 5ms CPU、5 次子请求、32KB 体积或需要存储KV/D1/R2、npm 包时应迁移到 Workers。执行模型Snippets 在请求路径上同步执行其完整执行流程如下请求到达 Cloudflare 边缘节点Ruleset Engine 评估 Snippet 规则过滤表达式如果规则匹配Snippet 在 5ms 限制内执行修改后的请求/响应继续沿管线传递响应返回给客户端。由于 Snippet 处于同步请求路径中性能至关重要——执行时间直接叠加到请求时延上这也是 5ms CPU 上限存在的原因。Snippet 通过export default { async fetch(request) {} }结构暴露入口与 Workers 的模块格式一致见 api.md。快速开始第一个 Snippet参考文档提供了一个添加安全响应头的最小示例可直接在 DashboardRules → Snippets中创建并部署// Snippet: Add security headers export default { async fetch(request) { const response await fetch(request); const newResponse new Response(response.body, response); newResponse.headers.set(X-Frame-Options, DENY); newResponse.headers.set(X-Content-Type-Options, nosniff); return newResponse; } }部署方式包括 DashboardRules → Snippets或 API / Terraform。此例展示了三个要点fetch(request)将请求转发到源站并拿到响应new Response(response.body, response)基于原响应克隆出新响应原对象不可变必须先克隆再修改newResponse.headers.set(...)设置安全头后返回。部署与配置四种方式参考文档configuration.md给出了四种配置方式覆盖从图形界面到基础设施即代码的全场景。1. Dashboard图形界面适合快速测试、单个 Snippet、可视化规则构建。操作步骤进入 zone → Rules → Snippets点击 Create Snippet 或选择模板输入 Snippet 名称仅限a-z、0-9、_创建后不可修改编写 JavaScript 代码最大 32KB配置 Snippet 规则Expression Builder可视化或 Expression Editor文本使用 Ruleset Engine 过滤表达式用 Preview / HTTP 标签页测试部署或保存为 Draft草稿。2. REST API适合 CI/CD、自动化与程序化管理。核心操作如下# Create/update snippetmultipart/form-data 上传代码文件 curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/snippets/$SNIPPET_NAME \ --request PUT \ --header Authorization: Bearer $CLOUDFLARE_API_TOKEN \ --form filesexample.js \ --form metadata{\main_module\: \example.js\} # Create snippet ruleJSON 定义触发规则 curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/snippets/snippet_rules \ --request PUT \ --header Authorization: Bearer $CLOUDFLARE_API_TOKEN \ --header Content-Type: application/json \ --data { rules: [ { description: Trigger snippet on /api paths, enabled: true, expression: starts_with(http.request.uri.path, \/api/\), snippet_name: api_snippet } ] } # List snippets curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/snippets \ --header Authorization: Bearer $CLOUDFLARE_API_TOKEN # Delete snippet curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/snippets/$SNIPPET_NAME \ --request DELETE \ --header Authorization: Bearer $CLOUDFLARE_API_TOKEN注意Snippet 规则端点接收的snippet_name必须与已创建的 Snippet 名称严格对应规则中的expression是 Ruleset Engine 表达式详见下文过滤表达式一节。3. Terraform适合基础设施即代码、多 zone 部署# Configure Terraform provider terraform { required_providers { cloudflare { source cloudflare/cloudflare version ~ 4.0 } } } provider cloudflare { api_token var.cloudflare_api_token } # Create snippet resource cloudflare_snippet security_headers { zone_id var.zone_id name security_headers main_module security_headers.js files { name security_headers.js content file(${path.module}/snippets/security_headers.js) } } # Create snippet rule resource cloudflare_snippet_rules security_rules { zone_id var.zone_id rules { description Apply security headers to all requests enabled true expression true snippet_name cloudflare_snippet.security_headers.name } }代码中通过cloudflare_snippet.security_headers.name建立资源间的显式依赖保证 Snippet 先于规则创建。4. Pulumi适合多云 IaC、TypeScript / Python / Go 工作流import * as cloudflare from pulumi/cloudflare; import * as fs from fs; // Create snippet const securitySnippet new cloudflare.Snippet(security-headers, { zoneId: zoneId, name: security_headers, mainModule: security_headers.js, files: [{ name: security_headers.js, content: fs.readFileSync(./snippets/security_headers.js, utf8), }], }); // Create snippet rule const snippetRule new cloudflare.SnippetRules(security-rules, { zoneId: zoneId, rules: [{ description: Apply security headers, enabled: true, expression: true, snippetName: securitySnippet.name, }], });认证方式API Token推荐在dash.cloudflare.com/profile/api-tokens创建需要权限Zone.Snippets:Edit与Zone.Rules:Edit然后export CLOUDFLARE_API_TOKENyour_token_hereAPI Key传统方式设置CLOUDFLARE_EMAIL与CLOUDFLARE_API_KEY两个环境变量。限制与要求资源限制备注Snippet 体积32 KB每个 Snippet压缩后Snippet 名称64 字符仅a-z、0-9、_不可变更每 zone Snippet 数20软限制可联系支持扩容每 zone 规则数20通常一个 Snippet 配一条规则表达式长度4096 字符每条规则表达式部署工作流开发阶段本地编写代码 → 用node snippet.js或 TypeScript 编译器做语法检查 → 部署到 Dashboard 或用 API 保存为 Draft → 用 Preview / HTTP 标签页测试 → 就绪后启用规则。生产阶段代码纳入版本控制 → 用 Terraform / Pulumi 保证可重复部署 → 先部署到 staging zone → 用低流量子域做真实流量验证 → 再应用到生产 zone → 用 Analytics / Logpush 持续监控。过滤表达式Ruleset Engine 触发语言Snippets 使用 Cloudflare Ruleset Engine 的表达式语言决定何时执行。参考文档configuration.md给出了完整的常用模式与函数清单。常见表达式模式// 主机匹配 http.host eq example.com http.host in {example.com www.example.com} http.host contains example // 路径匹配 http.request.uri.path eq /api/users starts_with(http.request.uri.path, /api/) ends_with(http.request.uri.path, .json) matches(http.request.uri.path, ^/api/v[0-9]/) // 查询参数 http.request.uri.query contains debugtrue // 请求头 http.headers[user-agent] contains Mobile http.headers[accept-language] eq en-US // Cookie http.cookie contains session // 地理位置 ip.geoip.country eq US ip.geoip.continent eq EU // Bot 检测需要 Bot Management cf.bot_management.score lt 30 // 方法 http.request.method eq POST http.request.method in {POST PUT PATCH} // 逻辑运算符组合 http.host eq example.com and starts_with(http.request.uri.path, /api/) ip.geoip.country eq US or ip.geoip.country eq CA not http.headers[user-agent] contains bot表达式函数函数示例说明starts_with()starts_with(http.request.uri.path, /api/)检查前缀ends_with()ends_with(http.request.uri.path, .json)检查后缀contains()contains(http.headers[user-agent], Mobile)检查子串matches()matches(http.request.uri.path, ^/api/)正则匹配lower()lower(http.host) eq example.com转小写upper()upper(http.headers[x-api-key])转大写len()len(http.request.uri.path) gt 100字符串长度表达式与 Snippet 代码分离是 Snippets 的核心设计规则决定何时触发代码决定如何修改这让同一个 Snippet 可以通过多条规则复用于不同流量。Snippet API 详解参考文档api.md系统梳理了请求与响应对象的完整用法。Request 对象HTTP 基础属性request.method // GET, POST, PUT, DELETE, etc. request.url // Full URL string request.headers // Headers object request.body // ReadableStream (for POST/PUT) request.cf // Cloudflare properties (see below)URL 操作const url new URL(request.url); url.hostname // example.com url.pathname // /path/to/page url.search // ?queryvalue url.searchParams.get(q) // value url.searchParams.set(q, new) url.searchParams.delete(q)头部操作注意request.headers是只读的修改前必须克隆// 读取 request.headers.get(User-Agent) request.headers.has(Authorization) request.headers.getSetCookie() // 获取所有 Set-Cookie 头 // 修改克隆新请求 const modifiedRequest new Request(request); modifiedRequest.headers.set(X-Custom, value) modifiedRequest.headers.delete(X-Remove)request.cf属性——访问 Cloudflare 附带的请求元数据是地理路由与 Bot 决策的数据基础// 地理位置 request.cf.city // San Francisco request.cf.continent // NA request.cf.country // US request.cf.region // California or CA request.cf.regionCode // CA request.cf.postalCode // 94102 request.cf.latitude // 37.7749 request.cf.longitude // -122.4194 request.cf.timezone // America/Los_Angeles request.cf.metroCode // 807 (DMA code) // 网络 request.cf.colo // SFO数据中心机场代码 request.cf.asn // 13335ASN 编号 request.cf.asOrganization // Cloudflare, Inc. // Bot Management若已启用 request.cf.botManagement.score // 1-991bot, 99human request.cf.botManagement.verified_bot // true/false request.cf.botManagement.static_resource // true/false // TLS/HTTP 版本 request.cf.tlsVersion // TLSv1.3 request.cf.tlsCipher // AEAD-AES128-GCM-SHA256 request.cf.httpProtocol // HTTP/2 // 请求元数据 request.cf.requestPriority // weight192;exclusive0典型应用场景地理路由、Bot 检测、安全决策与数据分析。Response 对象响应构造器// 纯文本 new Response(Hello, { status: 200 }) // JSON Response.json({ key: value }, { status: 200 }) // HTML new Response(h1Hi/h1, { status: 200, headers: { Content-Type: text/html } }) // 重定向 Response.redirect(https://example.com, 301) // or 302 // 流式透传原样转发 new Response(response.body, response)响应头部修改同样先克隆const newResponse new Response(response.body, response); newResponse.headers.set(X-Custom, value) newResponse.headers.append(Set-Cookie, sessionabc; Path/) newResponse.headers.delete(Server) newResponse.headers.set(Cache-Control, public, max-age3600) newResponse.headers.set(Content-Type, application/json)响应属性response.status // 200, 404, 500, etc. response.statusText // OK, Not Found, etc. response.headers // Headers object response.body // ReadableStream response.ok // true if status 200-299 response.redirected // true if redirectedREST API 端点速查操作端点说明列出 SnippetsGET /zones/{zone_id}/snippets枚举全部 Snippet获取 SnippetGET /zones/{zone_id}/snippets/{snippet_name}获取单个创建/更新 SnippetPUT /zones/{zone_id}/snippets/{snippet_name}multipart/form-data字段filessnippet.js与metadata{main_module:snippet.js}删除 SnippetDELETE /zones/{zone_id}/snippets/{snippet_name}删除单个列出 Snippet 规则GET /zones/{zone_id}/rulesets/phases/http_request_snippets/entrypoint规则在http_request_snippets阶段更新 Snippet 规则PUT /zones/{zone_id}/snippets/snippet_rulesJSON 规则数组其中列出规则端点揭示了 Snippets 的底层实现规则实际挂载在 Ruleset Engine 的http_request_snippets阶段入口entrypoint这与 README 中Snippets 作为 Ruleset Engine 的一部分运行的定位完全一致。可用 API 清单Snippets 运行在 V8 isolate 中提供的是Workers API 的子集✅ 支持fetch()— HTTP 请求按套餐 25 次子请求Request/Response— 标准 Web APIURL/URLSearchParams— URL 操作Headers— 头部操作TextEncoder/TextDecoder— 文本编解码crypto.subtle— Web Crypto API哈希、签名crypto.randomUUID()— UUID 生成另外在 gotchas.md 中还提到atob()/btoa()与JSON可用。❌ 不支持需改用 WorkerscachesAPIKV、D1、R2等存储 APIDurable Objects有状态对象WebSocket升级连接HTMLRewriterHTML 解析import语句不支持模块导入addEventListener— 必须使用export default { async fetch() {} }模式Node.js API。Snippet 标准结构export default { async fetch(request) { // Your logic here const response await fetch(request); return response; // or modified response } }七个实战模式参考文档patterns.md提供了可直接复用的真实场景代码覆盖了 Snippets 最常见的使用面。1. 安全响应头规则true所有请求export default { async fetch(request) { const response await fetch(request); const newResponse new Response(response.body, response); newResponse.headers.set(X-Frame-Options, DENY); newResponse.headers.set(X-Content-Type-Options, nosniff); newResponse.headers.delete(X-Powered-By); return newResponse; } }2. 基于地理位置的域名路由利用request.cf.country将欧洲用户 302 重定向到.eu域名export default { async fetch(request) { const country request.cf.country; if ([GB, DE, FR].includes(country)) { const url new URL(request.url); url.hostname url.hostname.replace(.com, .eu); return Response.redirect(url.toString(), 302); } return fetch(request); } }3. A/B 测试基于 Cookie 或随机数决定变体并通过Set-Cookie固定用户分组export default { async fetch(request) { const cookies request.headers.get(Cookie) || ; let variant cookies.match(/ab_test([AB])/)?.[1] || (Math.random() 0.5 ? A : B); const req new Request(request); req.headers.set(X-Variant, variant); const response await fetch(req); if (!cookies.includes(ab_test)) { const newResponse new Response(response.body, response); newResponse.headers.append(Set-Cookie, ab_test${variant}; Path/; Secure); return newResponse; } return response; } }4. Bot 检测拦截需要Bot Management 套餐。分数低于 30 判定为 Bot直接返回 403export default { async fetch(request) { const botScore request.cf.botManagement?.score; if (botScore botScore 30) return new Response(Denied, { status: 403 }); return fetch(request); } }5. API 内部认证头注入仅对/api/路径注入内部密钥并剥离外部Authorization头保护后端export default { async fetch(request) { if (new URL(request.url).pathname.startsWith(/api/)) { const req new Request(request); req.headers.set(X-Internal-Auth, secret_token); req.headers.delete(Authorization); return fetch(req); } return fetch(request); } }6. CORS 响应头处理预检请求OPTIONS并给正常响应补 CORS 头export default { async fetch(request) { if (request.method OPTIONS) { return new Response(null, { status: 204, headers: { Access-Control-Allow-Origin: *, Access-Control-Allow-Methods: GET, POST, PUT, DELETE, Access-Control-Allow-Headers: Content-Type, Authorization } }); } const response await fetch(request); const newResponse new Response(response.body, response); newResponse.headers.set(Access-Control-Allow-Origin, *); return newResponse; } }7. 维护模式持有X-Bypass-Token的内部请求放行其余返回 503 与Retry-Afterexport default { async fetch(request) { if (request.headers.get(X-Bypass-Token) admin) return fetch(request); return new Response(h1Maintenance/h1, { status: 503, headers: { Content-Type: text/html, Retry-After: 3600 } }); } }模式选择速查模式复杂度适用场景安全响应头低所有站点地理路由低区域内容分发A/B 测试中实验Bot 检测中需要 Bot ManagementAPI 认证注入低后端保护CORS低API 端点维护模式低部署窗口常见错误与排查参考文档gotchas.md总结了 Snippets 的典型错误码与解决思路。错误含义解决1000Snippet 执行失败运行时或语法错误用 try/catch 包裹代码1100超出执行限制CPU 5ms简化逻辑或迁移到 Workers1201多次源站 fetch只调用一次fetch(request)并复用响应1202子请求超限Pro 2 次Business/Enterprise 5 次减少 fetch 调用其他常见问题Cannot set property on immutable objectrequest/response不可变必须先克隆const modifiedRequest new Request(request);再修改头部caches is not definedSnippets 中没有 Cache API改用 WorkersModule not foundSnippets 不支持import改用内联代码或 Workers。错误处理示例try { return await fetch(request); } catch (error) { return new Response(Error: ${error.message}, { status: 500 }); }最佳实践性能保持代码 10KB上限 32KB代码越小冷启动与解析越快围绕 5ms CPU 上限优化算法与循环只在修改时克隆new Request(request)/new Response(response.body, response)避免无谓复制最小化子请求数量同一响应尽量复用。安全校验所有输入URL、头部、Cookie防止注入敏感数据的哈希/签名使用 Web Crypto APIcrypto.subtle转发到源站前清理外部传入的头部切勿在代码或日志中泄露密钥。调试在响应头中临时注入调试信息newResponse.headers.set(X-Debug-Country, request.cf.country);配合 curl 验证curl -H X-Test: true https://example.com -v性能基准参考操作时间设置响应头0.1msURL 解析0.2msfetch()1-3msSHA-256 哈希0.5-1ms该基准表明头部操作和 URL 解析非常廉价而fetch()是最昂贵的操作应作为优化的首要对象。何时迁移到 Workers当出现以下任一情况时应迁移到 Workers需要 5ms 执行时间、需要 5 次子请求、需要存储KV / D1 / R2、需要 npm 包、代码 32KB。Workers 虽然需要 $5/月起步的成本但提供完整的运行时能力两者组合使用可以构建规则级轻改造 应用级重逻辑的完整边缘架构。仓库中的阅读路径在 Cloudflare Deploy Skill 中Snippets 参考资料位于 references/snippets/推荐按以下顺序阅读configuration.md — 从这里开始设置、部署方式Dashboard / API / Terraform / Pulumiapi.md — 核心 APIRequest、Response、headers、request.cf属性patterns.md — 实战示例地理路由、A/B 测试、安全头gotchas.md — 故障排查常见错误、性能建议、API 限制。在 Skill 整体的能力地图SKILL.md中Snippets 与 Workers、Pages、Durable Objects、Workflows 等一同位列 Compute Runtime 分类当用户需要轻量级边缘逻辑修改 HTTP时决策树会优先指向本参考。若需深度验证或对比可进一步阅读 terraform 与 pulumi 参考以理解 IaC 编排或参考 wrangler/auth.md 了解部署前的认证检查流程。【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进