构建隐患(本次丢构建的根因)
- footer.html 用 resources.GetRemote 在每个页面渲染时拉 api/links 与 api/feeds,
构建节点连不上 Cloudflare 时重试撞穿 Hugo partial 30s 超时 → 整站构建失败
- 改为「流水线 curl 快照 + 模板读本地文件」:
· 新增 scripts/fetch_snapshots.sh,一次拉齐 conf / friend_links / friend_feeds
(--max-time 30 --retry 2,JSON 校验,失败一律删文件且恒 exit 0)
· .cnb.yml Hugo 构建 stage 改为调用该脚本
· footer.html 改读 site.Data.friend_links / site.Data.friend_feeds,缺失渲染空值
· .gitignore 忽略 /data/friend_links.json 与 /data/friend_feeds.json
- 降级实测:删掉快照后构建仍 EXIT=0,产物 friendLinks 为空数组
评论提交反馈(artalk.js 新增 __atkSubmit 模块)
- 校验:config.beforeSubmit 拦下 内容空 / 昵称空 / 邮箱空 / 邮箱格式错(网址不校验)
- 发送中:editor-submit 常驻 loading,超 7s 补「网络较慢」
- 成功:editor-submitted 按 normal/reply/edit 分文案,is_pending 提示等待审核
- 失败:拦 POST /api/v2/comments,403/429/4xx/5xx/网络异常全部翻译成人话
- 失败时输入内容保留,并清掉 Artalk 自带的重复小字通知
- 无头浏览器实测 19/19 通过(POST 走 mock,未向线上写数据)
友链申请卡片移动端
- max-width:640px 下隐藏 .atk-fl-nick(昵称 + 博主徽章),桌面端不变
改动:6 files, +282 / -61
74 lines
3.4 KiB
Bash
74 lines
3.4 KiB
Bash
#!/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 <输出文件名> <URL>
|
||
# 成功:原子替换(先写 .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
|