核心是用 c.IP() 判断是否在黑名单 map[string]struct{} 中,命中则 return c.Status(403).SendString("Forbidden");需提前配置 ProxyHeader 解决代理后 IP 问题,路径拦截用 strings.HasPrefix(c.Path(), "/api/"),白名单匹配成功应 return c.Next()。

怎么用中间件拦截黑名单 IP(直接拒绝)
核心是判断 c.IP() 是否在黑名单中,命中就立刻返回 403,且不调用 c.Next()。Fiber 不会自动中断流程,漏掉 return 就等于放行。
常见错误现象:IP 在黑名单里,但请求仍进到 handler;或返回 200 却没内容——本质是写了判断逻辑但忘了 return c.Status(403).SendString("Forbidden")。
- 黑名单建议用
map[string]struct{}或sync.Map(并发安全),避免每次遍历切片 - 别直接用
c.Get("X-Forwarded-For")—— 它可被伪造;若前端有可信反向代理(如 Nginx),应先配置app.Config().ProxyHeader = "X-Real-IP",再用c.IP()获取真实客户端 IP - 测试时注意:本地 curl 或浏览器发请求,
c.IP()通常是127.0.0.1,不是你预期的“公网 IP”
怎么放行白名单 IP(跳过后续中间件和路由)
白名单逻辑要放在中间件开头,匹配成功后直接 return c.Next(),让请求继续往下走;否则默认执行后续逻辑(比如鉴权、限流等)。
注意:白名单不是“只允许这些 IP 访问”,而是“这些 IP 不受后面某层限制”——它常和黑名单配合使用,或用于绕过限流/CORS 等非核心校验。
- 白名单 key 必须和黑名单一致(都用
c.IP()或统一的可信字段),否则出现“同个 IP 既被拦又被放” - 不要在白名单分支里写
c.SendString()后不return,那会导致响应体写出两次(Fiber 会 panic) - 若需支持 CIDR 段(如
192.168.1.0/24),用标准库net.ParseCIDR+ipNet.Contains(),别手写字符串匹配
如何让黑白名单对特定路径生效(比如只拦 /api/**)
Fiber 没有路径通配式开关,必须手动判断 c.Path() 或 c.OriginalURL()。推荐用 c.Path(),它不含 query 参数,更干净。
典型场景:静态资源 /public/* 和健康检查 /health 绝对不能被 IP 拦截;而 /api/v1/users 必须严格校验。
- 路径判断必须写在中间件最前面,避免无效计算
- 用
strings.HasPrefix(c.Path(), "/api/")而不是正则——轻量且无编译开销 - 别用
c.Route().Path:它返回的是路由定义模板(如/api/user/:id),不是当前请求的真实路径 - 如果用了
app.Group("/api", ipMiddleware),记得这个 group 里的所有子路由都会进中间件,无需再做路径判断
为什么加了中间件,但 CDN 或负载均衡后 IP 总是同一个
因为 c.IP() 默认取 RemoteAddr,在 Nginx、Cloudflare 等代理后,它变成网关 IP(如 10.0.0.1)。必须显式启用可信代理解析。
正确做法不是改中间件,而是初始化 app 时配置:
app := fiber.New(fiber.Config{
ProxyHeader: "X-Real-IP",
// 或 "X-Forwarded-For"(需确保上游只追加、不伪造)
})
然后中间件里继续用 c.IP() 即可拿到真实客户端 IP。若用 X-Forwarded-For,注意它可能是逗号分隔的多个 IP,需取第一个且过滤私有网段。
最容易被忽略的是:这个配置必须在 app.Use() 之前完成,否则中间件读不到修正后的 IP。


















