MisakaNet Proxy Worker (Cloudflare Worker)

August 15, 2026 · View on GitHub

注册代理 + 数据缓存层。支持两种功能:

  1. POST / — 节点注册(创建 Issue + 更新 counter + 发送欢迎消息)
  2. GET /api/counter / GET /api/lessons — 数据代理(带 GitHub Token 的 API 封装 + KV 缓存)

部署步骤

前置准备

  • Cloudflare 账号(免费版即可)
  • GitHub Personal Access Token(classic,scope: public_reporepo + issues:write

1. 创建 Worker

  1. 打开 https://dash.cloudflare.com/ → Workers & Pages
  2. 点 "Create Worker",选 "Hello World" 模板,命名(如 misakanet
  3. register-proxy.js 的内容全量粘贴到编辑器,点 "Save and Deploy"
  4. 记下 Worker 的 URL(如 https://misakanet.your-name.workers.dev

2. 设置环境变量

在 Worker 的 "Settings" → "Variables" 添加:

变量名说明
REGISTER_TOKENgithub_pat_xxxxxxxxGitHub PAT,需 contents:write + issues:write
MAINTAINER_KEY任意高强度随机字符串可选,保护 /api/insights/demand-map(未设置时该端点返回 503)

3. (可选)创建 KV Namespace

KV 用于缓存 counter.json / lessons.json 的响应,避免每次请求都调用 GitHub API。

  1. Workers & Pages → KV → "Create Namespace",命名如 MISAKANET_KV
  2. 复制 Namespace ID
  3. wrangler.jsonckv_namespaces 中替换 YOUR_KV_NAMESPACE_ID
  4. 或在 Dashboard 中 Worker 的 "Settings" → "Bindings" → "Add Binding"
    • 变量名: MISAKANET_KV
    • KV Namespace: 选择刚创建的

没有 KV 也能工作,只是每次请求都会调用 GitHub API(每小时 5000 次配额依然够用)。

4. 配置前端

  1. docs/index.html 中找到 WORKER_BASE 变量
  2. 将其值设为你的 Worker URL(如 https://misakanet.your-name.workers.dev
  3. 如果留空,前端将回退到 raw.githubusercontent.com 直接加载数据

5. 配置 GitHub Actions 部署(可选)

在仓库的 .github/workflows/ 中创建 deploy-worker.yml

name: Deploy Worker

on:
  push:
    branches: [main]
    paths:
      - "workers/register-proxy.js"
      - "wrangler.jsonc"

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to Cloudflare Workers
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CF_API_TOKEN }}
          workingDirectory: workers

API 端点

方法路径说明
GET/静态说明页
GET/api/counter返回 counter.json(JSON 对象)
GET/api/counter.json同上,兼容 .json 后缀
GET/api/lessons返回 lessons.json(JSON 数组)
GET/api/lessons.json同上,兼容 .json 后缀
GET/api/health健康检查,返回 Token / KV 配置状态
GET/api/helpful?lesson_id=<id>返回该 lesson 的 "helped me" 投票数
POST/节点注册(IP 限流 1 次/30s)

Insights endpoints (Issue #591)

方法路径说明
GET/api/insights/demand-board公开、仅聚合的需求看板:按 task family 统计 7d/30d 未解决次数,不含原始查询/日志/个人信息
GET/api/insights/demand-map维护者视图:按 taskFamily × bucketDay × unsolvedReason 展开的桶,需 X-Maintainer-Key 头匹配 MAINTAINER_KEY

Unsolved failure map (Issue #788)

方法路径说明
GET/api/insights/unsolved-map公开、仅聚合:30 天窗口内各 task family 的未解决次数(no_match / low_confidence / not_helpful)+ 被标记为无用的 lesson
GET/api/insights/lesson-coverage公开 lesson 覆盖看板:发布 lesson 数、family 覆盖率、covered / needs-review / uncovered gaps,以及 not-helpful lessons
GET/api/insights/reputation-leaderboard?period=all-time|monthly|weekly公开贡献者声誉榜:最多 20 名,读取 data/contributor-points.json,按时间窗口聚合历史积分
POST/api/search-signal前端在搜索无结果 / 低置信度时上报;Worker 在内存中把 query 归类到 task family 后立即丢弃原文,只写入聚合计数(IP 限流 30 次/分钟,body 上限 4KB)

隐私约束:只存储派生的 family 标签与固定枚举 reason,绝不写入原始 query、prompt、日志、路径或任何身份标识。 /api/feedback 收到 irrelevant / too_basic 时同样只写入聚合信号 + 公开 lesson ID。 公开页面:docs/insights/unsolved-map.htmlhttps://misakanet.org/insights/unsolved-map.html

公开覆盖看板:docs/insights/lesson-coverage.htmlhttps://misakanet.org/insights/lesson-coverage.html 公开声誉榜:docs/insights/reputation-leaderboard.htmlhttps://misakanet.org/insights/reputation-leaderboard.html

声誉点数是项目内部、不可转让且无现金价值的贡献记录;接口返回的 meta.cashValuemeta.transferable 始终为 false

node --test workers/unsolved-map.test.mjs   # 分类 / 聚合 / 隐私 / 限流单测

两个端点都不依赖 REGISTER_TOKEN,只依赖 MISAKANET_KV(数据源)与可选的 MAINTAINER_KEY(保护 demand-map)。数据来自 recordUnsolvedSignal(),供 intake 端点(#589)与分类器(#575)在报告/反馈/MCP 搜索未命中时调用写入;在这两个上游合并之前,看板会返回 available: true, summary: [](KV 已配置但暂无数据)。

Testing

# Unit-test task-family normalization, bucketing, windowing, and the maintainer-key gate
node --test workers/register-proxy.test.mjs

限流说明

  • 注册端 (POST): 每 IP 每 30 秒 1 次,基于 CF-Connecting-IP
  • 数据代理 (GET): 无 IP 限流(通过 GitHub Token + KV 缓存控制负载)
  • GitHub API 自身配额: 5000 req/h(带 Token),Worker 代为请求不消耗用户配额

架构说明

前端浏览器                      Cloudflare Worker                    GitHub
     │                              │                                  │
     │──── GET /api/counter ───────→│                                  │
     │                              │──── GET /contents/counter.json ─→│
     │                              │←─── Base64 JSON ────────────────│
     │                              │  ↓ Base64 解码 + 缓存到 KV      │
     │←─── JSON Response ──────────│                                  │
     │                              │                                  │
     │──── POST / (register) ──────→│                                  │
     │                              │──── POST /issues ──────────────→│
     │                              │──── PUT /contents/counter.json ─→│
     │                              │──── POST /issues/{n}/comments ─→│
     │←─── { success, node_num } ──│                                  │

Worker 的数据代理层解决了两个核心问题:

  1. GitHub API 匿名限速(60 req/h)→ Token 代理(5000 req/h)
  2. raw.githubusercontent.com CDN 不确定性 → KV 缓存(30s TTL)+ 主动失效机制

PR Genius Statistics

  • GET /api/insights/pr-genius: PR Genius workflow metrics, success rate, latency, and PR type distribution.