Claude Code 边缘计算实战:Workers、缓存与地域分流
用Claude Code设计Edge runtime:Workers、地域分流、缓存键、常见坑和验证命令。
边缘计算不是把所有后端都搬到离用户最近的地方,而是把“小而快的判断”放到靠近用户的运行环境里。比如地域跳转、短时间缓存、A/B测试分桶、预览页面的轻量鉴权,都可以在请求进入主应用之前完成。
但Edge runtime并不是万能加速按钮。它和普通Node.js服务器不同:可用API、执行时间、依赖包、请求元数据和缓存行为都有边界。如果只对Claude Code说“帮我改成边缘部署”,它很可能混入Node专用API,忘记把语言写进缓存键,或者把国家代码当成计费和权限判断依据。
本文以2026年6月2日确认过的官方资料为基础,整理Claude Code提示词、Cloudflare Workers可复制代码、Vercel Edge Middleware示例、迁移到Deno Deploy时的注意点,以及上线前验证命令。建议同时打开Cloudflare Workers、Workers Request API、Workers Cache API、Vercel Edge Runtime、Deno Deploy runtime和Claude Code overview。如果要深入单个平台,可以继续看Claude Code Cloudflare Workers指南和Claude Code Vercel Edge Functions指南。
先决定哪些逻辑适合Edge
最重要的第一步,是区分“入口判断”和“核心业务”。如果逻辑只需要URL、请求头、Cookie或很小的请求体,通常适合放在Edge。相反,深度数据库查询、长时间LLM调用、图片处理、PDF生成、账单结算和后台任务,最好留在普通API或队列中。
| 使用场景 | 适合Edge的原因 | 应留在后端的内容 |
|---|---|---|
| 国家或语言分流 | 可用国家代码或语言头快速选择入口 | 税费、发票、库存确认 |
| 短时间缓存 | 公开响应可以在近端复用 | DB更新和重新生成任务 |
| A/B测试分桶 | 页面渲染前即可读取Cookie | 统计判断和收入分析 |
| 轻量鉴权门禁 | 预览页、管理页可提前拦截 | 会话签发和权限审计 |
| Webhook入口校验 | 小请求体的签名可快速验证 | 支付处理、邮件、重试 |
把这张表放进Claude Code提示词,可以显著减少误生成。它会更清楚哪些代码应该在Edge里完成,哪些应该转交给源站API。
flowchart LR
User["User request"] --> Edge["Edge runtime"]
Edge --> Geo["Country / language branch"]
Edge --> Cache["Short cache"]
Edge --> Gate["Light auth gate"]
Edge --> Origin["Origin API / database"]
Origin --> Queue["Queue or background work"]
给Claude Code的提示词
边缘实现的提示词不要只写“让它更快”,而要写清楚限制。Claude Code能很快产出代码,但缓存键、地域分支、secret处理、验证命令这些细节如果不写明,最容易遗漏。
Implement a small Cloudflare Workers + TypeScript Edge runtime API.
Files:
- wrangler.toml
- src/index.ts
Requirements:
- GET /health returns JSON
- GET /api/edge-content returns locale and CTA copy based on country
- Use request.cf.country when Cloudflare provides it
- Also support a CF-IPCountry header for local curl verification
- Cache each locale separately for 60 seconds with the Cache API
- Return cache hit/miss through X-Edge-Cache
- Use Web APIs such as Request, Response, URL, and crypto; do not use Node-only APIs
- Include at least three curl or build commands that verify the behavior
Do not:
- Use pseudocode
- Hard-code API tokens or secrets
- Treat country code as proof for billing, permissions, or legal decisions
几个术语可以先说明。runtime就是代码运行的环境,cache key是查找缓存响应的名字,colo是Cloudflare数据中心标识。先解释这些词,Claude Code生成的注释和交接说明会更适合初学者。
Cloudflare Workers可复制示例
下面的Worker保持很小。/api/edge-content会读取Cloudflare请求元数据或本地测试请求头,将国家映射到语言,并用Cache API缓存60秒。本地可以用CF-IPCountry请求头模拟国家,所以不需要部署后才发现分流写错。
name = "claude-edge-router"
main = "src/index.ts"
compatibility_date = "2026-06-02"
[vars]
DEFAULT_LOCALE = "en"
// src/index.ts
export interface Env {
DEFAULT_LOCALE: string;
}
type Locale = "ja" | "en" | "zh" | "ko" | "es" | "fr" | "de" | "pt" | "hi" | "id";
type CfRequest = Request & {
cf?: {
country?: string;
colo?: string;
city?: string;
};
};
const SUPPORTED_LOCALES = new Set<Locale>([
"ja",
"en",
"zh",
"ko",
"es",
"fr",
"de",
"pt",
"hi",
"id",
]);
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === "/health") {
return json({ ok: true, runtime: "cloudflare-workers" });
}
if (url.pathname === "/api/edge-content") {
return handleEdgeContent(request, env, ctx);
}
return json({ error: "not_found" }, 404);
},
} satisfies ExportedHandler<Env>;
async function handleEdgeContent(
request: Request,
env: Env,
ctx: ExecutionContext
): Promise<Response> {
const url = new URL(request.url);
const country = getCountry(request);
const locale = localeFromCountry(country, env.DEFAULT_LOCALE);
const cacheKey = buildCacheKey(request, locale);
const cached = await caches.default.match(cacheKey);
if (cached) {
return withHeaders(cached, {
"X-Edge-Cache": "HIT",
"X-Edge-Locale": locale,
});
}
const body = {
locale,
country,
colo: getColo(request),
path: url.pathname,
cta: localizedCta(locale),
generatedAt: new Date().toISOString(),
};
const response = json(body, 200, {
"Cache-Control": "public, max-age=0, s-maxage=60, stale-while-revalidate=300",
"X-Edge-Cache": "MISS",
"X-Edge-Locale": locale,
});
ctx.waitUntil(caches.default.put(cacheKey, response.clone()));
return response;
}
function buildCacheKey(request: Request, locale: Locale): Request {
const url = new URL(request.url);
url.search = "";
url.pathname = `/__edge-cache/${locale}${url.pathname}`;
return new Request(url.toString(), { method: "GET" });
}
function getCountry(request: Request): string {
const cf = (request as CfRequest).cf;
return (
request.headers.get("CF-IPCountry") ||
request.headers.get("x-country") ||
cf?.country ||
"US"
).toUpperCase();
}
function getColo(request: Request): string {
return (request as CfRequest).cf?.colo || "local";
}
function localeFromCountry(country: string, fallback: string): Locale {
const normalizedFallback = SUPPORTED_LOCALES.has(fallback as Locale)
? (fallback as Locale)
: "en";
switch (country) {
case "JP":
return "ja";
case "CN":
case "TW":
case "HK":
return "zh";
case "KR":
return "ko";
case "ES":
case "MX":
case "AR":
return "es";
case "FR":
return "fr";
case "DE":
return "de";
case "BR":
case "PT":
return "pt";
case "IN":
return "hi";
case "ID":
return "id";
default:
return normalizedFallback;
}
}
function localizedCta(locale: Locale): string {
const messages: Record<Locale, string> = {
ja: "Claude Code教材を見る",
en: "Explore Claude Code templates",
zh: "查看 Claude Code 教材",
ko: "Claude Code 템플릿 보기",
es: "Ver plantillas de Claude Code",
fr: "Voir les modèles Claude Code",
de: "Claude Code Vorlagen ansehen",
pt: "Ver modelos de Claude Code",
hi: "Claude Code टेम्पलेट देखें",
id: "Lihat template Claude Code",
};
return messages[locale];
}
function json(data: unknown, status = 200, headers: HeadersInit = {}): Response {
return new Response(JSON.stringify(data, null, 2), {
status,
headers: {
"Content-Type": "application/json; charset=utf-8",
"X-Content-Type-Options": "nosniff",
...headers,
},
});
}
function withHeaders(response: Response, headers: Record<string, string>): Response {
const next = new Response(response.body, response);
for (const [key, value] of Object.entries(headers)) {
next.headers.set(key, value);
}
return next;
}
重点在缓存键。这里把locale写进/__edge-cache/${locale}${pathname},避免中文或日文CTA被错误复用给英语用户。同时清掉查询字符串,避免utm_source之类的广告参数把缓存切成很多无用条目。
扩展到Vercel和Deno
Vercel Edge Middleware适合在页面渲染前设置请求信息,例如国家、A/B测试桶和轻量跳转。使用它时要确认Edge Runtime限制,不要引入依赖Node专用API的库。
// middleware.ts
import { NextRequest, NextResponse } from "next/server";
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};
export function middleware(request: NextRequest) {
const country = request.headers.get("x-vercel-ip-country") || "US";
const bucket = request.cookies.get("edge_bucket")?.value || chooseBucket();
const response = NextResponse.next();
response.headers.set("x-edge-country", country);
response.headers.set("x-edge-bucket", bucket);
response.cookies.set("edge_bucket", bucket, {
maxAge: 60 * 60 * 24 * 30,
sameSite: "lax",
secure: true,
});
if (country === "JP" && request.nextUrl.pathname === "/pricing") {
return NextResponse.redirect(new URL("/jp/pricing", request.url));
}
return response;
}
function chooseBucket(): "a" | "b" {
const bytes = new Uint8Array(1);
crypto.getRandomValues(bytes);
return bytes[0] < 128 ? "a" : "b";
}
Deno Deploy也可以沿用Web标准的Request和Response。但不要把Cloudflare专属的request.cf照搬过去;供应商请求头和环境变量不同,应在提示词里明确说明。
// main.ts
Deno.serve((request: Request) => {
const url = new URL(request.url);
const country = request.headers.get("x-country") || "US";
if (url.pathname !== "/api/edge-content") {
return Response.json({ error: "not_found" }, { status: 404 });
}
return Response.json({
runtime: "deno-deploy",
country,
message: country === "JP" ? "Japan entry" : "Default edge entry",
});
});
验证命令
边缘代码至少要验证类型、本地HTTP、地域分支、缓存头和部署前配置。不要让Claude Code只说“已实现”,要让它留下可复查的命令和结果。
npm create cloudflare@latest claude-edge-router -- --type=hello-world
cd claude-edge-router
npm install -D typescript wrangler
npx wrangler types
npx tsc --noEmit
npx wrangler dev
另开终端执行curl。
curl -i http://127.0.0.1:8787/health
curl -i -H "CF-IPCountry: JP" http://127.0.0.1:8787/api/edge-content
curl -i -H "CF-IPCountry: US" http://127.0.0.1:8787/api/edge-content
curl -i -H "CF-IPCountry: JP" "http://127.0.0.1:8787/api/edge-content?utm_source=test"
npx wrangler deploy --dry-run
预期结果很直接:第一次同路径请求是X-Edge-Cache: MISS,同一语言和路径的下一次请求是HIT。JP映射到ja,US映射到en,带utm_source的请求不会创建单独缓存。
常见坑
第一个坑是把太多工作放到Edge。长LLM调用、复杂ORM查询、PDF生成、图片处理和账单流程通常不适合Edge。Edge应该是入口门禁,不应该承担整个后端。
第二个坑是缓存键设计不当。语言、登录状态、价格展示、实验桶会改变响应时,就必须进入缓存键。反过来,如果把utm_*、时间戳等噪声也放进缓存键,缓存命中率会很低。
第三个坑是过度信任地域信息。request.cf.country和x-vercel-ip-country适合用来设置默认体验,但不能作为税务、年龄、权限、计费的证明。VPN、企业代理和CDN路由都会影响它。
第四个坑是只给Claude Code一个平台名。“用Workers实现”并没有说明要用Cache API、KV、D1、Vercel兼容层还是源站回退。可以结合Claude Code serverless functions和性能优化指南来决定边界。
收益导线与下一步
在多语言内容站里,Edge runtime也能改善收益导线。你可以按语言展示免费PDF文案,把读者导向最合适的教材CTA,在缓存前清理广告参数,并让模板购买入口保持快速响应。
需要可复用模板时,可以查看ClaudeCodeLab产品列表。如果团队想统一Claude Code提示词、代码审查标准,以及Edge和Node的边界,可以看Claude Code培训与导入咨询。想先拿到简短流程,可以从免费速查表开始。
实际试用结果
这次更新中,Masa在本地Workers样例里切换CF-IPCountry: JP和CF-IPCountry: US,检查了locale、X-Edge-Cache以及去掉广告参数后的缓存键。验证时发现,本地测试最好先读取测试请求头,再回退到request.cf.country,否则连续测试时国家分支看起来会被固定住。缓存键也改成/__edge-cache/${locale}${pathname},避免不同地域内容混在一起。给Claude Code下指令时,最好明确要求它同时审查请求头优先级、地域分支和缓存键。
总结
边缘计算不是把一切搬到Edge,而是把能在入口快速判断的逻辑放到近端,重处理和最终判断仍留在普通API。把runtime限制、缓存键、地域分流和验证命令一起交给Claude Code,生成结果会更快,也更容易审查。
免费 PDF: Claude Code 速查表
输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。
我们会妥善保护你的信息,不发送垃圾邮件。
把 Claude Code 变成真正能带来结果的工作流
先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。
关于作者
Masa
专注 Claude Code 实务流程、团队导入和内容转化的工程师。
相关文章
Claude Code Permission Receipt Pattern:记录权限、证据和回滚方式
Claude Code 权限 receipt:记录允许动作、需要批准的边界、验证命令、回滚说明,以及 Gumroad 和咨询 CTA 检查。
Claude Code/Codex 安全 Agent Harness 实战:权限、验证与回滚
用权限策略、执行计划、验证脚本和回滚日志,为 Claude Code 与 Codex 搭建更安全的 AI Agent 工作流。
Claude Code 子代理实战指南:安全委派并行文章与代码工作
用 Claude Code 子代理安全拆分文章和代码工作:委派规则、提示词模板、失败模式与检查清单。