Skip to content

fix(leaderboard): 脚本 UA 换 Chrome 伪装 + 触发 redeploy 修首页 Top Rank 空#325

Closed
longsizhuo wants to merge 1 commit intomainfrom
fix/leaderboard-cf-challenge
Closed

fix(leaderboard): 脚本 UA 换 Chrome 伪装 + 触发 redeploy 修首页 Top Rank 空#325
longsizhuo wants to merge 1 commit intomainfrom
fix/leaderboard-cf-challenge

Conversation

@longsizhuo
Copy link
Copy Markdown
Member

故障

首页 Top Rank / /rank contributors 全部 "暂无数据"。

根因

PR #322 合并后 prod build 跑 `generate-leaderboard.mjs`,向 `api.involutionhell.com/api/public/leaderboard` 拉数据时被 Cloudflare Bot Fight Mode 拦下:
```
[generate-leaderboard] 后端返回 403 Forbidden,body 前 200 字符:

<title>Just a moment...</title>

[generate-leaderboard] 后端不可用,写入空榜单以放行构建。
```
脚本走 fallback 写空数组,prod `generated/site-leaderboard.json` 上线为 `[]`。

本 PR 改动

`scripts/generate-leaderboard.mjs`:UA 从 `InvolutionHell-build/1.0 (generate-leaderboard.mjs)` 改为标准 Chrome UA,避免 `build/script/bot` 关键词触发 CF UA 启发式判定。跟 backend OgFetchService 的 UA 伪装策略对齐。

修复路径

合并 → CI 触发 prod redeploy → `generate-leaderboard` 拉到真实 21 条数据 → 首页 Top Rank / /rank 恢复正常。

长期建议(不在本 PR 范围)

在 Cloudflare dashboard 给 `api.involutionhell.com/api/public/*` 加规则:

  • Action: Skip → "Browser Integrity Check" + "Bot Fight Mode"

公开匿名 API 永远不应该被 CF 挑战,否则任何 build / 爬虫 / 跨境集成都会偶发挂掉。

Test plan

  • 本地实测:新旧 UA 当前都能 200(CF 是基于 IP+时间窗+UA 综合评分,瞬时挑战)
  • tsc / vitest 通过
  • 合并后 prod build log 应能看到 `拉聚合数据:... → 200` 而不是 `403`
  • 首页 Top Rank 显示真实贡献者

故障复盘
PR #322 合并后 prod build 跑 generate-leaderboard.mjs 拿到 Cloudflare 的
403 + "Just a moment..." 挑战页,脚本走 fallback 写空数组上线,
首页 Top Rank / /rank contributors 全空。

根因
api.involutionhell.com 走 Cloudflare,默认 Bot Fight Mode 对短时间内多次
请求或低信誉 IP 段(Vercel build runner)会临时 challenge。当时虽然 UA 含
"build" 关键词加重了被拦概率,但实测换任意 UA 当下都能 200,所以本质是
CF 信誉评分 + 时间窗叠加。

本 PR
脚本 UA 从 "InvolutionHell-build/1.0 (generate-leaderboard.mjs)" 改为标准
Chrome UA,避免任何 "build/script/bot" 关键词触发 CF UA 启发式判定。
跟 backend OgFetchService 的 UA 伪装策略对齐。

长期建议(不在本 PR 范围)
在 Cloudflare 给 api.involutionhell.com/api/public/* 加规则:
  Action: Skip → "Browser Integrity Check" + "Bot Fight Mode"
让公开 API 永远绕过挑战。需要在 CF dashboard 操作。

修复路径
合并 → CI 触发 prod redeploy → generate-leaderboard 拉到真实 21 条 →
首页 Top Rank / /rank contributors 恢复正常。
Copilot AI review requested due to automatic review settings April 26, 2026 18:51
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 26, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
involutionhell-github-io Ready Ready Preview, Comment Apr 26, 2026 7:03pm
website-preview Ready Ready Preview, Comment Apr 26, 2026 7:03pm

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses production leaderboard/top-rank data showing as empty by preventing Cloudflare Bot Fight Mode from challenging the build-time fetch to api.involutionhell.com/api/public/leaderboard. It updates the leaderboard generation script to use a mainstream Chrome User-Agent so the backend request is less likely to be classified as automated traffic during CI builds.

Changes:

  • Replace the custom build/script User-Agent with a standard Chrome UA in fetch headers.
  • Add inline rationale explaining the Cloudflare challenge behavior and the intended long-term fix (CF rule).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@longsizhuo longsizhuo closed this Apr 27, 2026
longsizhuo pushed a commit that referenced this pull request Apr 27, 2026
PR #325 自身的 preview build 仍被 CF 403 拦下(log 显示 "Just a moment..."),
说明 UA 伪装救不了——CF 是基于 Vercel runner 的 IP 段信誉评分,跟 UA 无关。
真正的根治是去 CF 给 /api/public/* 加 "Skip Bot Fight" 规则(用户操作)。

本次至少把"一次失败抹好数据"这个二次伤害堵住:
- 拉到数据      → 正常生成
- 拉不到 + 旧 JSON 有非空数组 → 保留旧版,warn 日志,exit 0
- 拉不到 + 旧 JSON 空/损坏     → 写空数组兜底(首次 build 不挂)
- 拉不到 + 旧 JSON 不存在      → 写空数组兜底

效果:
即便 CF 后续仍偶发拦截,prod 上线的 leaderboard 也只会"维持上一版"
而不是"突然空了"。Top Rank 不会因为一次 build 抖动整块消失。
longsizhuo pushed a commit that referenced this pull request Apr 27, 2026
PR #325 自身的 preview build 仍被 CF 403 拦下(log 显示 "Just a moment..."),
说明 UA 伪装救不了——CF 是基于 Vercel runner 的 IP 段信誉评分,跟 UA 无关。
真正的根治是去 CF 给 /api/public/* 加 "Skip Bot Fight" 规则(用户操作)。

本次至少把"一次失败抹好数据"这个二次伤害堵住:
- 拉到数据      → 正常生成
- 拉不到 + 旧 JSON 有非空数组 → 保留旧版,warn 日志,exit 0
- 拉不到 + 旧 JSON 空/损坏     → 写空数组兜底(首次 build 不挂)
- 拉不到 + 旧 JSON 不存在      → 写空数组兜底

效果:
即便 CF 后续仍偶发拦截,prod 上线的 leaderboard 也只会"维持上一版"
而不是"突然空了"。Top Rank 不会因为一次 build 抖动整块消失。
longsizhuo added a commit that referenced this pull request Apr 27, 2026
…325) (#326)

* fix(leaderboard): 脚本 UA 换 Chrome 伪装规避 CF Bot Fight

故障复盘
PR #322 合并后 prod build 跑 generate-leaderboard.mjs 拿到 Cloudflare 的
403 + "Just a moment..." 挑战页,脚本走 fallback 写空数组上线,
首页 Top Rank / /rank contributors 全空。

根因
api.involutionhell.com 走 Cloudflare,默认 Bot Fight Mode 对短时间内多次
请求或低信誉 IP 段(Vercel build runner)会临时 challenge。当时虽然 UA 含
"build" 关键词加重了被拦概率,但实测换任意 UA 当下都能 200,所以本质是
CF 信誉评分 + 时间窗叠加。

本 PR
脚本 UA 从 "InvolutionHell-build/1.0 (generate-leaderboard.mjs)" 改为标准
Chrome UA,避免任何 "build/script/bot" 关键词触发 CF UA 启发式判定。
跟 backend OgFetchService 的 UA 伪装策略对齐。

长期建议(不在本 PR 范围)
在 Cloudflare 给 api.involutionhell.com/api/public/* 加规则:
  Action: Skip → "Browser Integrity Check" + "Bot Fight Mode"
让公开 API 永远绕过挑战。需要在 CF dashboard 操作。

修复路径
合并 → CI 触发 prod redeploy → generate-leaderboard 拉到真实 21 条 →
首页 Top Rank / /rank contributors 恢复正常。

* fix(leaderboard): fallback 优先保留旧 JSON,避免一次拉失败抹掉好数据

PR #325 自身的 preview build 仍被 CF 403 拦下(log 显示 "Just a moment..."),
说明 UA 伪装救不了——CF 是基于 Vercel runner 的 IP 段信誉评分,跟 UA 无关。
真正的根治是去 CF 给 /api/public/* 加 "Skip Bot Fight" 规则(用户操作)。

本次至少把"一次失败抹好数据"这个二次伤害堵住:
- 拉到数据      → 正常生成
- 拉不到 + 旧 JSON 有非空数组 → 保留旧版,warn 日志,exit 0
- 拉不到 + 旧 JSON 空/损坏     → 写空数组兜底(首次 build 不挂)
- 拉不到 + 旧 JSON 不存在      → 写空数组兜底

效果:
即便 CF 后续仍偶发拦截,prod 上线的 leaderboard 也只会"维持上一版"
而不是"突然空了"。Top Rank 不会因为一次 build 抖动整块消失。

* fix(leaderboard): UA 改回 InvolutionHell-SSR 让 CF Custom Rule 真正匹配

之前误判
昨天看到 build 拿 403 + "Just a moment..." 时,第一反应是"UA 含 build 关键词
触发 CF UA 启发式",于是把 UA 改成 Chrome 伪装。错了。

实际 CF 配置
api.involutionhell.com 上有一条 Custom Rule:
  (http.host eq "api.involutionhell.com"
   and http.user_agent contains "InvolutionHell-SSR")
  → Skip: Bot Fight Mode / Browser Integrity Check / Managed Rules

也就是说 CF **明确依赖 UA token "InvolutionHell-SSR"** 来识别"自己人"放行。
Chrome 伪装恰恰把这个 token 拿掉,规则不匹配,Vercel runner 仍然按 IP
信誉被 Bot Fight 拦下回 403。

本 PR
脚本 UA 改成
  "InvolutionHell-SSR/1.0 (build; generate-leaderboard.mjs; +https://involutionhell.com)"
带上 CF 规则要求的 token。本机实测 200 + 21 条数据正常返回。

效果
合并后 prod build → CF 规则匹配 Skip → 拉到真实数据 → site-leaderboard.json
回到 21 条 → 首页 Top Rank / /rank contributors 恢复显示。

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants