WHAT - 微服务统一入口配置原理

文章目录

  • 什么是反向代理
  • [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 还提供 SetURLSetXForwarded 来处理目标地址与代理头。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 网关平台。

相关推荐
Erishen3 小时前
能算的绝不调模型:resolve-harness 的确定性 Fast Path 运行时
架构·开源
阿拉斯攀登3 小时前
CTF-Web题型刷题思路:CTFHub、攻防世界题型拆解
架构
阿拉斯攀登3 小时前
CTF-Writeup规范:解题思路、漏洞分析、复盘总结
架构
TunerT_TQ3 小时前
智能体评测的哲学——当“跑分”不再等于“能力”|第0期 · 序章
安全·架构·agent
JouYY3 小时前
我用DSH高效管理了我的prompt收藏
架构·llm·agent
岁月如歌77863 小时前
分布式锁完全指南:从数据库到 Redisson 的演进
java·后端·架构
阿拉斯攀登3 小时前
中间件漏洞专项:Tomcat、Nginx、Apache漏洞复现与修复
架构
潮族大Z4 小时前
App 架构演进:MVC → MVP → MVVM → MVI,一篇看懂
架构
2601_962218474 小时前
万象生鲜系统智能报表引擎技术为生鲜企业提供数字化经营分析能力
大数据·运维·微服务·云原生·架构