维护模式中间件需拦截所有请求但放行健康检查与静态资源,通过路径白名单(如/health、/assets)和环境变量/redis统一开关控制,并对非api路径返回index.html以支持spa,且必须置于中间件链顶端。

维护模式中间件必须拦截所有请求,但要放行健康检查和静态资源
维护模式不是简单返回 503,而是得区分「谁该被拦、谁该放行」。硬写 c.Status(503).SendString("maintenance") 会把 /health、/metrics、/favicon.ico 全部挡住,监控告警直接失灵。
正确做法是用路径前缀 + 白名单判断:
- 维护开关建议存在环境变量或配置中心(如
MaintenanceMode=true),避免改代码发版 - 白名单路径写死在中间件里,比如
["/health", "/readyz", "/metrics", "/assets"],不依赖路由注册顺序 - 对静态资源路径(如
/assets)放行时,要确保它在维护中间件之前已挂载,否则static.New()根本没机会执行
如何让维护响应不干扰前端 SPA 路由回退
如果项目是 Vue/React SPA,用户刷新页面时浏览器会发 GET 请求到当前路由(如 /dashboard/settings)。维护中间件若直接返回 503,前端就收不到 HTML,整个页面白屏——这不是维护,是崩溃。
解决方案是:对非 API 路径(即不以 /api 开头的请求),返回 index.html 并加 HTTP 头提示状态:
if !strings.HasPrefix(c.Path(), "/api") {
c.Set("X-Maintenance", "true")
return c.SendFile("./public/index.html")
}
c.Status(503).JSON(fiber.Map{"error": "service under maintenance"})
这样前端能捕获 X-Maintenance 头,自己渲染维护页;用户也不会看到空白或 503 错误页。
多实例部署下,维护开关必须全局一致
用 os.Getenv("MaintenanceMode") 在每个实例读本地环境变量,看似简单,但上线时你得逐台机器改环境变量,极易漏掉或不一致。
生产环境应对接外部协调服务:
- 首选 Redis:用
GET maintenance:enabled,所有实例共享一个 key - 次选 etcd 或 Consul:支持监听变更,开关生效延迟可压到 100ms 内
- 禁用文件轮询(如读取
/tmp/maint.flag):K8s Pod 重启后状态丢失,且文件 I/O 在高并发下成瓶颈
注意:Redis 查询必须带超时(如 client.Get(ctx, "maintenance:enabled").Timeout(200 * time.Millisecond)),避免单点故障拖垮整个服务链路。
维护中间件不能影响其他中间件的执行逻辑
常见错误是在中间件里写了 c.Status(503).Send(...) 后还调 c.Next()。Fiber 规定:一旦响应头已写出(status code 已设),再调 c.Next() 不会报错,但后续 handler 的 c.Send() 会静默失败,日志里也看不到异常。
务必保证「拒绝即终止」:
- 所有分支最终都要有明确出口:要么
return,要么c.Next() - 不要在中间件里调
c.Locals()存状态再传给下游——维护模式下根本不会走到下游 - 如果用了
limiter或logger等中间件,维护中间件必须放在它们之前,否则限流计数器还在跑、日志还在刷,徒增无谓开销
最易被忽略的是:维护中间件的启用时机。它必须在 app.Use() 链最顶端注册,否则像 cors.New() 这类中间件可能先处理了 OPTIONS 预检请求,导致维护响应被 CORS 头污染,前端拿不到原始 503。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











