JDK17 HttpClient响应处理核心是statusCode()、headers()、body()三大方法,分别获取状态码、响应头和泛型类型响应体,对应HTTP协议的响应结果、面单备注与货物内容。

别用 ctx.Send() 直接转发,这是最常见错误
很多人一上来就写 http.DefaultClient.Do() 拼请求,结果发现 Body 为空、Header 丢了一半、大文件卡死、SSE 断连。根本原因是:c.Body() 只能读一次,且 http.DefaultClient 默认不复用连接,MaxIdleConnsPerHost=2,压测几秒就报 dial tcp: too many open files。
更隐蔽的问题是:Fiber 的 ctx.Request().Body 已被框架内部提前读取(比如解析 form 或 multipart),你再调 c.Body() 实际拿到的是空字节流。
- 绝对不要手动构造
http.Request并用http.Client发起转发 - 不要在
Director函数里做限流或鉴权——逻辑应前置到 Fiber 路由层 - 避免用
io.Copy直接转发响应体,它不处理Transfer-Encoding: chunked或Content-Length缺失场景
正确组合:用 httputil.NewSingleHostReverseProxy + Fiber 路由控制
Fiber 本身不是代理库,它的定位是轻量路由和中间件编排。真正扛转发的必须是标准库的 httputil.ReverseProxy,它原生支持流式响应、Header 透传、连接复用和错误重试。
关键实操点:
- 每个后端服务配一个独立的
*httputil.ReverseProxy实例,别共用 - 显式设置
Director:改写req.URL.Host和req.URL.Scheme,并用strings.TrimPrefix(req.URL.Path, "/api")剥离前缀 - 自定义
Transport:设MaxIdleConnsPerHost = 100,启用KeepAlive,避免连接耗尽 - 在 Fiber 路由中调
proxy.ServeHTTP(c.Response().Writer, c.Request().Request),而不是自己拼 response
X-Forwarded-* 头没生效?检查 server.forward-headers-strategy 是否配对
如果你的 Fiber 网关前面还套了一层 Nginx / Ingress,而 Spring Boot 后端收不到真实 IP 或 HTTPS 协议,大概率不是 Fiber 没传头,而是 Spring Boot 没解析——它默认忽略所有 X-Forwarded-* 头。
必须在 Spring Boot 的 application.yml 里加:
server: forward-headers-strategy: framework
这个配置会激活 ForwardedHeaderFilter,让 request.getRemoteAddr() 返回 X-Forwarded-For 第一项,request.getScheme() 返回 X-Forwarded-Proto 值。
- 别设成
native:那是 Tomcat 自己解析,但 Fiber 转发时不会自动加RemoteIPValve - 别漏掉 Nginx 配置:必须有
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;等对应指令 - Fiber 侧要确保透传这些头:在
Director里显式补上,比如req.Header.Set("X-Forwarded-For", c.Get("X-Forwarded-For"))
路径匹配和 Host 处理容易出 404
Fiber 对路径匹配很严格。如果你注册了 app.Post("/api/users", ...),但 Nginx 或 ngrok 把请求发来的是 /api/users/(带尾部斜杠),或者 Host 是 example.ngrok.io 而你只认 localhost,就会直接 404。
实操建议:
- 用通配符路由兜底:
app.All("*", func(c *fiber.Ctx) error { return c.Status(404).SendString("not found") }) - 别依赖
c.Hostname()做路由判断,优先读c.Get("X-Forwarded-Host")(Nginx/ngrok/frp 都会带) - 如果后端要求 Host 必须是特定值,用
req.Header.Set("Host", "backend.example.com")在Director里覆盖 - 开发期可临时禁用严格校验:
app.Server().StrictContentLength = false,避免 chunked 请求被拒
真正难的不是写转发逻辑,而是厘清每一层谁该负责什么:Fiber 管路由、鉴权、打标;httputil.ReverseProxy 管连接、流、头透传;Nginx 管 SSL 终结和负载分发;Spring Boot 管头还原。任何一层越界做事,都会埋下偶发性故障。


















