Cloudflare API 常用编程模式实战:基于官方 SDK 的全量分页、自动重试与批量并发操作
【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills
本文是 Cloudflare API 集成参考中“Common Patterns”一文的完整实战化展开,聚焦于使用官方 SDK(TypeScript / Python / Go)应对分页、限流、批量操作等真实业务场景的通用代码模式。读完本文,你将掌握全量数据遍历、指数退避重试、受控并发、Zone 与 DNS 记录 CRUD、条件更新与容错批处理等可直接落地的开发技巧,并理解这些模式背后的限流阈值与 SDK 行为。
一、模式总览与适用前提
Cloudflare API 采用 REST 风格接口(https://api.cloudflare.com/client/v4/...),所有官方 SDK 均由 OpenAPI 规范自动生成(Stainless 生成,API 形态在各语言间保持一致),因此 TypeScript、Python、Go 三种语言可以共享同一套模式思想。本指南涉及的“Common Patterns”覆盖以下高频场景:
- List All with Auto-Pagination:API 返回分页结果,默认每页 20 条,需要遍历全部数据;
- Error Handling with Retry:限流(429)与瞬时错误需要自动重试;
- Batch Parallel Operations:快速创建多个资源,同时避免触发限流;
- Zone CRUD Workflow:域名(Zone)的增删改查标准流程;
- DNS Bulk Update:批量修改 DNS 记录;
- Filter and Collect Results:按条件过滤并收集结果;
- Error Recovery Pattern:自定义的显式重试与等待逻辑;
- Conditional Update Pattern:满足状态条件才执行更新;
- Batch with Error Handling:批量操作中单条失败不影响整体。
使用这些模式前,需要先完成 SDK 客户端初始化和认证配置,详见 API 参考 与 配置说明;关于限流阈值与常见错误的深入排查,可参考 陷阱与排障。
二、准备阶段:客户端初始化与认证
2.1 各语言客户端初始化
三种官方 SDK 的初始化方式如下(完整示例见 api.md):
// TypeScript import Cloudflare from 'cloudflare'; const client = new Cloudflare({ apiToken: process.env.CLOUDFLARE_API_TOKEN, });# Python from cloudflare import Cloudflare client = Cloudflare(api_token=os.environ.get("CLOUDFLARE_API_TOKEN")) # 异步场景使用 AsyncCloudflare from cloudflare import AsyncCloudflare client = AsyncCloudflare(api_token=os.environ["CLOUDFLARE_API_TOKEN"])// Go import ( "github.com/cloudflare/cloudflare-go/v4" "github.com/cloudflare/cloudflare-go/v4/option" ) client := cloudflare.NewClient( option.WithAPIToken(os.Getenv("CLOUDFLARE_API_TOKEN")), )提示:Python 的同步客户端
Cloudflare与异步客户端AsyncCloudflare不能混用——对同步客户端执行await会抛出TypeError,反之亦然(详见 gotchas.md)。
2.2 认证方式与重试等基础配置
推荐使用具备最小权限的 API Token(可在 Dashboard → My Profile → API Tokens 中创建,建议按 zone 授权并设置有效期),而非全局的 API Key + Email。SDK 默认配置为:超时 60 秒、重试 2 次(Go SDK 默认为 10 次),可按需调整:
const client = new Cloudflare({ apiToken: process.env.CLOUDFLARE_API_TOKEN, timeout: 120000, // 2 分钟(默认 60s),单位毫秒 maxRetries: 5, // 默认 2 });三、全量分页遍历:List All with Auto-Pagination
问题场景:API 返回分页结果,默认每页大小为 20 条,直接调用 list 只会拿到第一页。
解决方案:使用 SDK 内置的自动分页迭代器,一次性遍历全部结果。
// TypeScript for await (const zone of client.zones.list()) { console.log(zone.name); }# Python for zone in client.zones.list(): print(zone.name)// Go iter := client.Zones.ListAutoPaging(ctx, cloudflare.ZoneListParams{}) for iter.Next() { fmt.Println(iter.Current().Name) }为什么必须用自动分页?如果不使用迭代器,例如const page = await client.zones.list(),只能拿到前 20 条记录,这就是典型的“分页截断”陷阱(Pagination Truncation,见 gotchas.md)。正确的做法是用for await...of(TS)/ 迭代器协议(Python)/ListAutoPaging(Go)持续拉取后续页,直到所有结果返回完毕。部分端点单页上限可到 50 条,但依赖具体端点行为,一律使用自动分页最为稳妥。
四、错误处理与自动重试:应对 429 限流
问题场景:请求触发限流(HTTP 429)或出现瞬时网络错误,需要自动重试。
解决方案:官方 SDK 内置了指数退避(exponential backoff)自动重试,并尊重服务端返回的Retry-After响应头;重试耗尽后抛出RateLimitError。默认重试次数为 2(Go 为 10),可针对限流密集的操作调大:
// 为限流密集型操作增加重试次数 const client = new Cloudflare({ maxRetries: 5 }); try { const zone = await client.zones.create({ /* ... */ }); } catch (err) { if (err instanceof Cloudflare.RateLimitError) { // 已按退避策略自动重试 5 次 const retryAfter = err.headers['retry-after']; console.log(`Rate limited. Retry after ${retryAfter}s`); } }需要了解的限流阈值(来自 gotchas.md):
| 限制项 | 数值 |
|---|---|
| 每用户/每 Token 全局限额 | 1200 次请求 / 5 分钟 |
| 每 IP 限额 | 200 次请求 / 秒 |
| GraphQL 限额 | 320 次 / 5 分钟(基于成本计费) |
常见错误类型(完整定义见 api.md):
AuthenticationError(401):Token 无效或未设置;PermissionDeniedError(403):Token 权限范围不足;NotFoundError(404):资源不存在;RateLimitError(429):超出限流;InternalServerError(≥500):Cloudflare 侧故障。
五、批量并行操作:Batch Parallel Operations
问题场景:需要快速创建多个资源。
解决方案:使用Promise.all()并行发起请求,同时注意控制并发以规避限流。
// 并行创建多个 DNS 记录 const records = ['www', 'api', 'cdn'].map(subdomain => client.dns.records.create({ zone_id: 'zone-id', type: 'A', name: `${subdomain}.example.com`, content: '192.0.2.1', }) ); await Promise.all(records);受控并发(避免触发限流):当子域数量很大时,直接用Promise.all可能瞬间打满配额。推荐引入p-limit限制最大并发数:
import pLimit from 'p-limit'; const limit = pLimit(10); // 最大 10 个并发 const subdomains = ['www', 'api', 'cdn', /* 更多子域 */]; const records = subdomains.map(subdomain => limit(() => client.dns.records.create({ zone_id: 'zone-id', type: 'A', name: `${subdomain}.example.com`, content: '192.0.2.1', })) ); await Promise.all(records);经验值:官方建议并行请求数控制在10 以内(见 gotchas.md 的 Limits Reference),同时配合提高
maxRetries,可在批量任务中显著降低 429 概率。
六、Zone CRUD 标准工作流
Zone(域名)的完整生命周期操作如下,覆盖创建、读取、更新、删除四步:
// Create 创建 const zone = await client.zones.create({ account: { id: 'account-id' }, name: 'example.com', type: 'full', // 或 'partial'(部分接入) }); // Read 读取 const fetched = await client.zones.get({ zone_id: zone.id }); // Update 更新 await client.zones.edit(zone.id, { paused: false }); // Delete 删除 await client.zones.delete(zone.id);Go 语言注意点:Go SDK 对可选字段要求使用cloudflare.F()包装器,用于区分零值、null 与未传字段三种状态(详见 gotchas.md):
zone, err := client.Zones.New(ctx, cloudflare.ZoneNewParams{ Account: cloudflare.F(cloudflare.ZoneNewParamsAccount{ ID: cloudflare.F("account-id"), }), Name: cloudflare.F("example.com"), Type: cloudflare.F(cloudflare.ZoneNewParamsTypeFull), })不带cloudflare.F()直接传字符串将无法编译或不会发送该字段,这是 Go SDK 与 TS/Python 最显著的差异。
七、DNS 批量更新:DNS Bulk Update
问题场景:将某个子域的所有 A 记录指向新的 IP。
实现思路:先用自动分页拉取全部 A 记录,再并行执行更新。
// 1. 拉取全部 A 记录 const records = []; for await (const record of client.dns.records.list({ zone_id: 'zone-id', type: 'A', })) { records.push(record); } // 2. 全部更新到新 IP await Promise.all(records.map(record => client.dns.records.update({ zone_id: 'zone-id', dns_record_id: record.id, type: 'A', name: record.name, content: '203.0.113.1', // 新 IP proxied: record.proxied, ttl: record.ttl, }) ));注意更新时必须回传name、content、proxied、ttl等字段,因为 DNS 记录的更新是整条替换语义;若记录数量很大,建议配合p-limit控制并发,并将maxRetries调高以应对限流。单条记录的创建与更新参数说明可对照 api.md:ttl: 1表示自动 TTL,proxied: true表示开启橙色云代理。
八、过滤与收集结果:Filter and Collect Results
问题场景:在分页遍历的同时按业务条件过滤记录。
解决方案:在for await循环内做条件判断并收集匹配项:
// 找出所有开启了代理(proxied)的 A 记录 const proxiedRecords = []; for await (const record of client.dns.records.list({ zone_id: 'zone-id', type: 'A', })) { if (record.proxied) { proxiedRecords.push(record); } }该模式与“全量分页遍历”一脉相承:先借助自动分页保证数据完整,再在客户端侧做过滤,适合 list 接口过滤参数无法完全表达业务条件的场景。
九、错误恢复模式:自定义显式重试
SDK 的自动重试属于“黑盒”行为;当你需要完全掌控重试节奏(例如打印日志、控制等待时长、限制总尝试次数)时,可以手写显式重试包装器:
async function createZoneWithRetry(name: string, maxAttempts = 3) { for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { return await client.zones.create({ account: { id: 'account-id' }, name, type: 'full', }); } catch (err) { if (err instanceof Cloudflare.RateLimitError && attempt < maxAttempts) { const retryAfter = parseInt(err.headers['retry-after'] || '5'); console.log(`Rate limited, waiting ${retryAfter}s (retry ${attempt}/${maxAttempts})`); await new Promise(resolve => setTimeout(resolve, retryAfter * 1000)); } else { throw err; } } } }核心要点:
- 只在
RateLimitError且未达到最大尝试次数时重试,其余错误直接抛出; - 优先读取
Retry-After响应头作为等待时长,缺失时回退到默认值(示例中为 5 秒); - 与 SDK 自动重试的取舍:若需要“快速失败”(如用户态请求),可将
maxRetries设为 0 并自行处理(见 configuration.md)。
十、条件更新模式:Conditional Update Pattern
问题场景:只有在资源处于特定状态时才执行更新,避免误操作。
解决方案:先读取资源状态,再决定是否写入:
// 仅当 Zone 处于 active 状态时才取消暂停 const zone = await client.zones.get({ zone_id: 'zone-id' }); if (zone.status === 'active') { await client.zones.edit(zone.id, { paused: false }); }这种“读-判-写”三步式条件更新,适合任何对前置状态有要求的变更操作(例如仅对active域名执行 DNS 改动),是避免竞态与误更新的基础防御手段。
十一、带错误处理的批量操作:Batch with Error Handling
问题场景:批量处理多个 Zone,希望单条失败不中断整体,且能区分成功与失败。
解决方案:使用Promise.allSettled()并行执行并收集每个任务的结局:
// 批量处理多个 Zone,出错继续执行 const results = await Promise.allSettled( zoneIds.map(id => client.zones.get({ zone_id: id })) ); results.forEach((result, i) => { if (result.status === 'fulfilled') { console.log(`Zone ${i}: ${result.value.name}`); } else { console.error(`Zone ${i} failed:`, result.reason.message); } });与Promise.all的“任一失败即整体失败”不同,Promise.allSettled保证所有请求都会执行完毕,并通过status === 'fulfilled' | 'rejected'分支分别处理成功结果与失败原因,非常适合批量巡检、批量同步等容错要求高的任务。
十二、模式选择速查与延伸阅读
| 场景 | 推荐模式 | 关键 API / 依赖 |
|---|---|---|
| 遍历全部分页数据 | 自动分页迭代器 | for await/ListAutoPaging |
| 应对 429 限流 | SDK 自动重试 +maxRetries | RateLimitError |
| 大批量创建 | p-limit受控并发 | p-limit,并发 ≤ 10 |
| 更新全部匹配记录 | 遍历 + 批量 update | dns.records.update |
| 按条件收集 | 遍历内过滤 | list + 客户端判断 |
| 完全掌控重试 | 手写createZoneWithRetry | Retry-After头 |
| 条件更新 | 读-判-写 | zones.get→zones.edit |
| 容错批处理 | Promise.allSettled | 逐个结果处理 |
本指南对应的原始参考文档位于 patterns.md,同目录下的配套资料可继续深入:
- api.md:SDK 客户端初始化、认证、分页、错误类型与 Zone/DNS 基础操作;
- configuration.md:SDK 配置项(timeout / maxRetries / baseURL)、环境变量与 Wrangler 集成;
- gotchas.md:限流阈值、SDK 特有坑点(Go
F()包装器、Python 同步/异步客户端)、Token 权限表与排障清单; - README.md:Cloudflare API 集成总览与阅读顺序。
一个重要的架构提醒:如果你是在 Workers 运行时内部调用 Cloudflare 能力,bindings 参考 明确指出应优先使用绑定(bindings)而非 REST API——Worker 的 subrequest 会计入 API 限流,而绑定(如env.MY_KV、env.MY_BUCKET)在运行时零开销、不计入限流。REST API 与本文所述模式主要适用于服务端程序(Node/Python/Go)与脚本/CI 场景,请按 决策树 选择正确的调用方式。
【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考