🚀 技术复盘:基于 Cloudflare Workers 的 GitHub API 缓存代理方案 / A GitHub API Caching Proxy Built with Cloudflare Workers
1. 项目背景与痛点
在开发个人项目(如 Daily-Plan 计划展示)时,需要动态获取 GitHub 仓库的目录结构。
最初尝试:使用 raw.githubusercontent.com
- 局限:只能请求单个文件内容,无法获取文件夹下的文件列表
进阶尝试:直接在前端调用 api.github.com 的 Trees 接口
- 痛点:触发了 GitHub 的 Rate Limit(限流)
- 报错:HTTP 403 Forbidden
- 原因:对于未认证的请求,GitHub 限制每小时仅 60 次,由于 Cloudflare 等 CDN 节点的 IP 共享,额度极易耗尽
2. 核心解决方案:边缘计算代理层
为了彻底解决限流并加速访问,引入了 Cloudflare Workers 作为中间件,构建了一套"带缓存的云端代理"架构。
🏗️ 系统架构图
用户访问 -> Cloudflare Worker
|
├──[缓存命中]--> 直接返回 (< 100ms)
|
└──[缓存缺失]--> GitHub API (Token认证)
|
↓
存入 KV 缓存
|
↓
返回数据🌐 云缓存地址
https://daily-plan-api.jatenliu16.workers.dev3. 技术实现细节
核心组件
| 组件 | 作用 |
|---|---|
| Worker (逻辑层) | 处理请求转发、异常捕获与缓存逻辑 |
| KV Storage (存储层) | 分布式键值对数据库,持久化存储 API 响应 |
| Secrets (安全层) | 隐藏 GitHub PAT,防止密钥泄露 |
前端调用代码
javascript
// 优先访问 Cloudflare 缓存,失败则用 GitHub Token
async function fetchHistory() {
const cacheUrl = "https://daily-plan-api.jatenliu16.workers.dev/";
let response = await fetch(cacheUrl);
if (!response.ok) {
// Fallback: 直接用 GitHub Token 请求
response = await fetch(
"https://api.github.com/repos/Tidenflow/Daily-Plan/git/trees/main?recursive=1",
{
headers: {
Accept: "application/vnd.github.v3+json",
Authorization: "token ghp_xxxx", // 你的 GitHub Token
},
}
);
if (!response.ok) throw new Error("Failed to fetch");
}
const data = await response.json();
return parseHistoryTree(data.tree || []);
}Worker 服务端代码
javascript
export default {
async fetch(request, env) {
const CACHE = env.HISTORY; // KV 命名空间
// 1. 尝试读取缓存
if (CACHE) {
const cached = await CACHE.get('history');
if (cached) {
return new Response(cached, {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
});
}
}
// 2. 缓存缺失,请求 GitHub API
const res = await fetch(
'https://api.github.com/repos/Tidenflow/Daily-Plan/git/trees/main?recursive=1',
{
headers: {
'Accept': 'application/vnd.github.v3+json',
'Authorization': `token ${env.GH_TOKEN}` // 从 Secret 读取
}
}
);
const data = await res.json();
// 3. 存入缓存 (1小时过期)
if (CACHE) {
await CACHE.put('history', JSON.stringify(data), { expirationTtl: 3600 });
}
return new Response(JSON.stringify(data), {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
});
}
};4. 方案对比
| 维度 | 优化前 (直接请求) | 优化后 (Worker 代理) |
|---|---|---|
| 访问限流 | 每小时 60 次 (IP共享) | 每小时 5000 次 + 缓存保护 |
| 响应速度 | 1~2 秒 (国际链路) | < 100ms (边缘命中) |
| 安全性 | 暴露仓库/Token | 隐藏所有敏感信息 |
| 稳定性 | GitHub 波动即白屏 | 缓存可支撑 1 小时 |
5. 部署 Checklist
Step 1: 创建 Worker
- 打开 Cloudflare Dashboard
- Workers → 创建 Worker
- 名称:
daily-plan-api - 粘贴代码并部署
Step 2: 绑定 KV
- 进入 Worker → 设置 → 变量
- 创建 KV 命名空间:
HISTORY - 返回 Worker → 设置 → 绑定 → 添加
- 类型: KV namespace,名称:
HISTORY,选择刚创建的命名空间
Step 3: 添加 GitHub Token (可选)
- Worker → 设置 → 变量
- 添加 Secret:
GH_TOKEN - 值: 你的 GitHub Personal Access Token
注意事项
- ✅ CORS: 必须包含
'Access-Control-Allow-Origin': '*' - ✅ User-Agent: GitHub API 强制要求
- ✅ 缓存 TTL: 建议 3600 秒 (1小时)