#!/usr/bin/env bash # ============================================================================= # 构建期数据快照 —— 把「模板渲染时必须用、但只能从远端拿」的数据先 curl 成本地文件 # ============================================================================= # 为什么必须这么做(2026-10-04 实战教训): # footer.html 原先用 resources.GetRemote 拉 /api/links 与 /api/feeds。Hugo 的 # GetRemote 是**在模板渲染过程中同步发请求**的,而 footer 每个页面都要走一遍。 # 构建节点(国内)到 api.200181.xyz(Cloudflare)一旦抖动: # WARN Links API fetch failed: dial tcp 104.21.58.236:443: i/o timeout # WARN Links API fetch failed: ... connection reset by peer # Artalk 无关,但这两个拉取会一直重试 → 撞穿 Hugo 的 `partial` 30 秒超时 → # ERROR render of "home" failed: partial "footer.html" timed out after 30s # Error: error building site → exit code: 1 # 整站构建失败、站点不更新(实测白等 14.5 分钟)。 # # 改成「stage 里 curl 一次 + 模板只读本地文件」后: # 网络问题最多让某个快照变旧/为空(模板 with 判空 → 渲染空值), # **永远不会再让构建挂掉**。命中失败时一律删文件,绝不留半截内容。 # # 在流水线里由 .cnb.yml 的「Hugo 构建」stage 调用;本地预览想拿到同款数据 # 也可以直接跑:bash scripts/fetch_snapshots.sh # # 产物(均在 .gitignore 里,不入库): # data/artalk_conf.json 评论 /conf(首屏省一跳跨境往返,见 partials/artalk.html) # data/friend_links.json 友链 → window.friendLinks(评论区「友链」徽章) # data/friend_feeds.json 友圈 → window.friendFeeds(评论区「友圈」徽章) # ============================================================================= set -u BASE="${RSSAPI_BASE:-https://api.200181.xyz}" BASE="${BASE%/}" ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" DATA_DIR="$ROOT/data" mkdir -p "$DATA_DIR" # JSON 合法性校验:python3 不一定有(本机 Windows 可能没有),没有就跳过校验 validate_json() { command -v python3 >/dev/null 2>&1 || return 0 python3 -c 'import json,sys;json.load(open(sys.argv[1],encoding="utf-8"))' "$1" 2>/dev/null } # snap <输出文件名> # 成功:原子替换(先写 .tmp 再 mv),并打印字节数 # 失败:删除目标文件(含 .tmp),返回非 0 —— 但本脚本最后统一 exit 0, # 因为「快照拿不到」是可接受的降级,不该阻断构建。 snap() { local name="$1" url="$2" out tmp ok=1 out="$DATA_DIR/$name" tmp="$out.tmp" if curl -fsS --max-time 30 --retry 2 --retry-delay 2 --retry-connrefused \ -H 'User-Agent: hugo-build-snapshot' "$url" -o "$tmp" 2>/dev/null; then if [ -s "$tmp" ] && validate_json "$tmp"; then mv -f "$tmp" "$out" echo "✅ $name 就绪 $(wc -c < "$out" | tr -d ' ') 字节" return 0 fi echo "⚠️ $name 内容校验失败(空文件或非法 JSON)" else echo "⚠️ $name 拉取失败:$url" fi rm -f "$tmp" "$out" return 1 } echo "── 构建期快照(源:$BASE)──" snap artalk_conf.json "$BASE/api/v2/conf" || true snap friend_links.json "$BASE/api/links?all=1" || true snap friend_feeds.json "$BASE/api/feeds" || true exit 0