feat(ops): 健康检查端点,并把上传超时与服务端读超时对齐

1) /healthz 与 /readyz
   改动前站内唯一的「探活」手段是 curl /,而首页只渲染模板、不查数据库:
   DB 挂了首页照样 200(漏报),Redis 挂了首页又可能 500(误报)。
   监控、CDN 源站健康检查、滚动重启的摘流判定都没有可靠依据。
   → /healthz 永远 200,刻意不碰任何依赖:进程活着 ≠ 能对外服务,
     把 DB 检查塞进存活探针会导致数据库抖动时进程被反复重启,对恢复毫无帮助;
   → /readyz 查 DB(2s 超时),失败 503;响应体只回组件状态,
     绝不回错误详情 —— 这是公开端点,DB 报错常带库名/主机名/账号。
   实测:停掉 PostgreSQL 后 /healthz 仍 200、/readyz 503,恢复后 200。

2) ReadTimeout 30s → 120s
   站内允许单图 8MB、请求体上限 12MB。30s 传完 8MB 需要 ≥273 KB/s 上行,
   而手机 4G 上行常在 1–2 Mbps(125–250 KB/s)—— 一张 8MB 图必然超时,
   且用户已写好的正文会一起丢(POST 失败不回填)。120s 对应约 68 KB/s,
   偏远地区 3G 也能过。
   放宽它不会让 slowloris 重新可行:那类攻击卡在「发不完 header」,
   由 10s 的 ReadHeaderTimeout 拦住,ReadTimeout 只影响读完 header 之后传 body 的时长。
This commit is contained in:
tamakyi
2026-10-29 16:28:44 +08:00
parent 0124e392c7
commit f2e0c43083
4 changed files with 99 additions and 2 deletions
+7
View File
@@ -319,6 +319,13 @@ func New() *flamego.Flame {
reqUserSignIn := context.Toggle(&context.ToggleOptions{UserSignInRequired: true})
f.Group("", func() {
// 健康检查:存活(永远 200)与就绪(DB 可用才 200,否则 503)。
// 免鉴权、不限流、不查业务数据;响应体不含任何内部错误详情。
// 注意:这两个端点仍会经过全局中间件(安全头、IP 黑名单、自动封禁),
// 这是有意保留的 —— 异常来源不该因为「探针路径」就绕过封禁。
f.Get("/healthz", route.Healthz)
f.Get("/readyz", route.Readyz)
f.Get("/", route.Home)
f.Get("/pixel", reqUserSignIn, pixel.Index)
f.Get("/sponsor", route.Sponsor)