文章目录
- 什么是反向代理
- [Go 的 `httputil.ReverseProxy`](#Go 的
httputil.ReverseProxy) - [`Rewrite` 在做什么](#
Rewrite在做什么) - 自己写网关不只是"转发一下"
- [`ReverseProxy` 适合什么情况](#
ReverseProxy适合什么情况) - [Nginx 适合什么情况](#Nginx 适合什么情况)
- [Kong / APISIX 适合什么情况](#Kong / APISIX 适合什么情况)
- 怎么选
微服务的统一入口:
text
客户端
↓
API 网关 / 反向代理
├── /users → 用户服务
├── /posts → 文章服务
└── /orders → 订单服务
客户端不需要知道每个微服务的地址,只访问网关。
什么是反向代理
普通代理代表客户端访问服务器;反向代理代表服务器集群接收客户端请求。
假设内部服务是:
text
用户服务:http://user-service:8081
文章服务:http://post-service:8082
外部只暴露:
text
https://api.example.com
网关按照路径转发:
text
GET /users/1
↓
http://user-service:8081/users/1
GET /posts/10
↓
http://post-service:8082/posts/10
响应再由网关转发回客户端。
Go 的 httputil.ReverseProxy
Go 标准库提供:
go
import "net/http/httputil"
一个最小网关示例:
go
package main
import (
"encoding/json"
"log"
"net/http"
"net/http/httputil"
"net/url"
"time"
)
func newProxy(target string) (*httputil.ReverseProxy, error) {
targetURL, err := url.Parse(target)
if err != nil {
return nil, err
}
proxy := &httputil.ReverseProxy{
Rewrite: func(req *httputil.ProxyRequest) {
req.SetURL(targetURL)
req.SetXForwarded()
req.Out.Header.Set("X-Gateway", "blog-gateway")
},
ErrorHandler: func(
w http.ResponseWriter,
r *http.Request,
err error,
) {
log.Printf("代理请求失败: %v", err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadGateway)
_ = json.NewEncoder(w).Encode(map[string]string{
"error": "upstream service unavailable",
})
},
}
return proxy, nil
}
func main() {
userProxy, err := newProxy("http://localhost:8081")
if err != nil {
log.Fatal(err)
}
postProxy, err := newProxy("http://localhost:8082")
if err != nil {
log.Fatal(err)
}
mux := http.NewServeMux()
mux.Handle("/users/", userProxy)
mux.Handle("/posts/", postProxy)
server := &http.Server{
Addr: ":8080",
Handler: mux,
ReadHeaderTimeout: 5 * time.Second,
ReadTimeout: 15 * time.Second,
WriteTimeout: 30 * time.Second,
IdleTimeout: 60 * time.Second,
}
log.Println("gateway listening on :8080")
log.Fatal(server.ListenAndServe())
}
ReverseProxy 会修改目标请求、调用下游服务,再把下游响应复制给原客户端;现代 API 还提供 SetURL 和 SetXForwarded 来处理目标地址与代理头。Go httputil.ReverseProxy
Rewrite 在做什么
go
Rewrite: func(req *httputil.ProxyRequest) {
req.SetURL(targetURL)
req.SetXForwarded()
}
其中:
go
req.In
是客户端发给网关的原始请求,不应该修改。
go
req.Out
是网关准备发给下游服务的新请求。
go
req.SetURL(targetURL)
设置下游服务地址。
go
req.SetXForwarded()
加入:
http
X-Forwarded-For
X-Forwarded-Host
X-Forwarded-Proto
下游服务可以据此知道:
- 原始客户端 IP;
- 客户端访问的域名;
- 原始请求使用 HTTP 还是 HTTPS。
自己写网关不只是"转发一下"
真正的生产网关通常还要考虑:
- 路由匹配;
- 服务发现;
- 负载均衡;
- 身份认证;
- 权限校验;
- 限流;
- 请求体大小限制;
- 超时;
- 熔断;
- 重试;
- 日志和指标;
- Trace ID 传递;
- TLS;
- 灰度发布;
- 跨域;
- WebSocket;
- 下游不可用时的统一错误格式。
ReverseProxy 提供的是转发基础能力,其余能力通常需要自己实现。
特别注意,重试不能无脑应用到所有请求:
text
GET 通常可以谨慎重试
POST /payments
POST /orders
不能随意重试,否则可能重复扣款或重复创建订单
写请求需要配合幂等键。
ReverseProxy 适合什么情况
比较适合:
- 微服务数量较少;
- 路由规则比较固定;
- 需要大量 Go 定制逻辑;
- 实现面向某个前端的 BFF;
- 内部系统;
- 团队愿意维护网关代码;
- 不需要完整的 API 管理平台。
例如 BFF:
text
Web 前端
↓
Go BFF
├── 请求用户服务
├── 请求订单服务
├── 聚合结果
└── 返回前端需要的结构
这种情况下 Go 网关不只是转发,还可能组合多个服务的数据,因此自己写比较自然。
Nginx 适合什么情况
Nginx 更偏向成熟的通用反向代理:
nginx
upstream user_service {
server user-service-1:8081;
server user-service-2:8081;
}
server {
listen 80;
location /users/ {
proxy_pass http://user_service;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
它适合处理:
- TLS 终止;
- 静态文件;
- 反向代理;
- 负载均衡;
- 超时和请求体限制;
- 缓存;
- 基础限流;
- 成熟稳定的边缘接入。
相关配置以 proxy_pass 和代理请求头为核心。Nginx proxy module
如果需求只是:
text
域名 + HTTPS + 路径转发 + 负载均衡
Nginx 往往比自己写 Go 网关省事。
Kong / APISIX 适合什么情况
Kong 和 APISIX 更接近完整的 API 网关平台。
它们通常适合:
- 服务数量较多;
- 路由需要动态更新;
- 多团队共同使用;
- 统一认证;
- 按用户或接口限流;
- 插件化日志和监控;
- API Key、JWT 等认证;
- 灰度和流量治理;
- 希望通过控制面管理路由。
结构通常是:
text
管理接口 / 配置中心
↓
Kong / APISIX
├── 认证插件
├── 限流插件
├── 日志插件
├── 路由规则
└── 上游负载均衡
↓
微服务集群
可以参考 Kong Gateway 文档 和 Apache APISIX 文档。
怎么选
| 场景 | 建议 |
|---|---|
| 两三个服务,只需简单转发 | Nginx |
| 需要 Go 编写定制逻辑或 BFF | httputil.ReverseProxy |
| 服务多、团队多、需要插件治理 | Kong / APISIX |
| Kubernetes 环境 | Ingress/Gateway + 必要时独立 API 网关 |
| 既要边缘接入又要业务聚合 | Nginx/API Gateway + Go BFF |
这些方案也可以组合:
text
互联网请求
↓
Nginx / Kong / APISIX
├── TLS
├── 限流
├── WAF
└── 统一认证
↓
Go BFF
├── 聚合业务数据
└── 调用内部微服务
一般当路由、租户、鉴权、限流和服务治理越来越复杂,再考虑 Kong/APISIX。
httputil.ReverseProxy是网关的代码积木;Nginx 是成熟的反向代理服务器;Kong/APISIX 是带管理和插件能力的 API 网关平台。