有同学问,Nginx 能做反向代理,Gateway 也能做,功能上似乎重叠了,那为什么还要在 Spring Cloud Gateway 前面再加一层 Nginx 呢?
这么想,其实是把视角局限在了功能点上。从架构层面看,这两者的定位非常清晰:Nginx 是网络流量网关,而 Spring Cloud Gateway 是业务网关。
它们并非竞争关系,而是上下游的协作关系。在微服务架构的流量链路中,正常流程应该是:用户 → Nginx → Spring Cloud Gateway → 微服务。
下面的 API 网关架构图就很直观:Nginx 负责接收公网流量,分发到 Gateway 集群;而 Spring Cloud Gateway 则作为内网业务逻辑的统一入口,进行鉴权、限流和路由。

下面,具体聊聊为什么还需要 Nginx。
1. 静态资源访问
现在项目基本都是前后端分离的,后端服务返回业务数据,但前端的那些 HTML、CSS、JS、图片,谁来高效地提供服务呢?
Nginx 处理静态文件有天然的优势。它不用把文件数据读到用户态内存,而是直接通过内核态的 sendfile 系统调用,让磁盘文件直接转发给网卡,全程几乎没有 CPU 拷贝开销。这种性能,用 Java 来处理是远远比不上的。
Gateway 底层基于 Netty,虽然也用到了零拷贝技术,但数据处理路径依然是:磁盘 → 内核缓冲区 → Netty 缓冲区 → 网卡。在高并发的静态资源请求下,性能远不如 Nginx。让它去处理静态文件,有点像开跑车去拉砖,不是不能干,而是性价比极低。流量治理,比如路由转发、限流熔断、灰度发布、鉴权过滤这些,才是它的长处。
Nginx 还能做“动静分离”。当请求进来时,它可以这样判断:
- 匹配
/api/** 的路径,转发给 Gateway 去处理业务逻辑。
- 匹配
.html、.js、.css 或图片等请求,Nginx 直接返回静态资源。
这种毫秒级的响应,用户体验非常流畅。把这些请求交给 Java 服务去处理,反而容易出现页面“转圈”等待的情况。

2. 谁来给网关做负载均衡?
你可能会问,Gateway 自己也是个 Java 服务,怎么保证高可用?线上关键服务肯定不能只部署一台,万一挂了,所有业务服务都无法访问了。通常至少得部署 3 台组成一个集群。
那么问题来了:前端请求过来,到底发给 IP1、IP2 还是 IP3 呢?
这就需要 Nginx 了。它负责将流量均衡地分发到后端的各个 Gateway 节点上,为 Gateway 集群提供一个统一的流量入口。没有 Nginx 在前面挡着,Gateway 集群就成了没有大门的一堆房子。

3. SSL 卸载
配置域名通常要上 HTTPS,而 SSL/TLS 握手过程涉及复杂的非对称加密运算,非常消耗 CPU 资源。
如果在 Gateway 这一层做 SSL 握手,业务线程很可能会被这些计算密集型的解密操作所阻塞,导致整个系统的吞吐量下降。
更合理的做法是在 Nginx 层统一配置 SSL 证书,由它来负责 HTTPS 流量的解密,这被称为“SSL 卸载”。解密之后,再通过内网以明文 HTTP 的方式转发给 Gateway。像这类与核心业务无关的脏活累活,就应该交给 Nginx 去做,让 Java 服务更专注于业务逻辑处理。

4. 运维与开发互不干扰
个人觉得这一点最重要,它把职责边界划分得清清楚楚。
- 运维关注 Nginx 层:负责封禁恶意 IP、调整 gzip 压缩比、配置跨域头、升级 OpenSSL 补丁等。这些变更修改的是网络层的配置,实时生效,风险可控,完全不用重启 Java 服务。
- 开发关注 Gateway 层:负责修改路由规则、调整鉴权逻辑、修改参数校验规则等。这些变更通过代码发布的正常流程进行迭代,不会影响到底层的网络配置。
试想一下,如果不做分层,运维想封禁一个恶意 IP,还得去求着开发改代码、走发版流程。这不仅流程繁琐、效率低下,还特别容易引发扯皮。

说在最后
多一层网络转发,不一定是性能浪费。在内网千兆网络环境下,Nginx 转发到 Gateway 的延迟几乎可以忽略不计。
Nginx 和 Gateway 定位不同,职责各异,谈不上谁能取代谁。在 云栈社区 我们也常讨论这类架构选择。只有让它们互相配合,才能构建出稳定、高性能且易于维护的微服务系统架构。