Gateway
约 2823 字大约 9 分钟
2025-02-27
1. Gateway 简介
SpringCloud Gateway 是 Spring Cloud 官方提供的 API Gateway 框架,它是基于 Spring 5、Spring Boot 2 和 Project Reactor 的异步非阻塞 HTTP 服务网关。它旨在通过提供一系列的功能来帮助开发人员创建基于微服务架构的 API 网关。
Gateway 网关是我们服务的守门神,所有微服务的统一入口。
2. Gateway 作用
Gateway 网关的作用主要有以下几点:
- 统一认证和授权:Gateway 网关提供统一的认证和授权功能,对所有微服务的请求进行鉴权,只有经过认证和授权的请求才可以访问微服务。
- 动态路由:Gateway 网关支持动态路由,通过配置路由规则,可以将请求路由到对应的微服务。
- 熔断机制:Gateway 网关支持熔断机制,当微服务出现故障时,Gateway 网关会自动将请求转移到其他微服务,保障微服务的高可用。
- 限流降级:Gateway 网关支持限流降级,当微服务的请求量过大时,Gateway 网关会自动限制流量,保障微服务的稳定运行。
- 静态响应处理:Gateway 网关支持静态响应处理,对于一些特殊的请求,Gateway 网关可以直接返回固定响应,避免请求转发到微服务。
3. Gateway 架构
Gateway 网关的架构主要分为以下几个部分:
- Gateway Server:Gateway 网关的服务端,它主要负责接收客户端的请求,并根据路由规则转发请求到对应的微服务。
- Gateway Client:Gateway 网关的客户端,它主要负责向 Gateway Server 发送请求,并接收微服务的响应。
- Route Definition:路由定义,它是 Gateway 网关的核心配置,它定义了请求的转发规则,包括匹配条件、路由目标地址、predicates 和 filters。
- Predicates:断言,它是 Gateway 网关的匹配条件,它可以对请求进行多种匹配,包括 Path、Header、Host、Method 等。
- Filters:过滤器,它是 Gateway 网关的请求处理逻辑,它可以对请求进行多种处理,包括修改请求头、重写请求路径、限流、熔断等。
4. Gateway 工作流程
Gateway 网关的工作流程如下图所示:

Gateway 网关的工作流程可以分为以下几个步骤:
- 客户端向 Gateway Server 发送请求。
- Gateway Server 根据路由规则,匹配请求的目标微服务。
- Gateway Server 向目标微服务发送请求。
- 目标微服务处理请求,并返回响应。
- Gateway Server 接收到目标微服务的响应,并根据路由规则,生成响应给客户端。
5. Zuul 与 Gateway 的区别
Zuul 是一个基于 Netflix 的开源项目,它是 Spring Cloud 的一部分,Zuul 2 已经不再维护,Zuul 1 已经停止维护。
Gateway 网关是 Spring Cloud 官方提供的 API Gateway 框架,它是基于 Spring 5、Spring Boot 2 和 Project Reactor 的异步非阻塞 HTTP 服务网关。它旨在通过提供一系列的功能来帮助开发人员创建基于微服务架构的 API 网关。
目前在cloud官网当中新版本已经将zuul彻底移除了。Zuul1.0已经进入了维护阶段,而Gateway是SpringCloud团队研发的,是亲儿子产品,值得信赖。而且很多功能Zuul都没有用起来也非常的简单便捷。在版本选型上我们基本上不会再考虑zuul了。
总的来说,Gateway 网关是 Spring Cloud 官方推荐的 API Gateway 框架,Zuul 1.0 已经停止维护,Zuul 2 已经不再维护,所以我们基本上不会再考虑 zuul 了。
6. Gateway实战
6.1 创建 syh-gateway 模块
6.2 引入依赖并注册 Gateway
pom.xml
<dependencies>
<!--网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--
Spring Cloud Gateway 2.2.0 版本开始,默认使用 Spring Cloud LoadBalancer 作为负载均衡器。
-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
application.yml
server: # 服务器配置
port: 9527 # 端口号
spring: # Spring配置
application: # Spring Boot应用配置
name: syh-gateway # Spring Boot应用名称
cloud: # Spring Cloud配置
gateway: # 网关配置
routes: # 路由配置
- id: oms-service # 路由ID
# uri: http://localhost:8090
uri: lb://oms-service # 路由地址
filters: # 过滤器配置
predicates: # 断言配置
- Path=/oms/** # 路径匹配
我们将符合Path 规则的一切请求,都代理到 uri参数指定的地址。 上面的例子中,我们将 /oms/** 开头的请求,代理到 lb://oms-service,其中 lb 是负载均衡(LoadBalance),根据服务名拉取服务列表,实现负载均衡。
注:Spring Cloud Gateway 2.2.0 版本开始,默认使用 Spring Cloud LoadBalancer 作为负载均衡器。所以要导入spring-cloud-starter-loadbalancer依赖
通过以上示例,我们可以基本的掌握Gateway到底是干什么的,说白了就是请求转发。
7. Gateway 常用配置
7.1 路由配置
- id:路由ID,用于区分不同的路由规则。
- uri:路由地址,即请求转发的目标地址。lb://代表负载均衡,从注册中心获取目标微服务的实例列表,并且负载均衡选择一个访问。
- predicates:路由断言,用于匹配请求的条件。
- filters:路由过滤器,用于对请求进行处理。
ymal配置示例:
spring:
cloud:
gateway:
routes:
- id: oms-service
uri: lb://oms-service
predicates:
- Path=/oms/**
filters:
- StripPrefix=1
java配置示例:
@Configuration
public class GateWayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("path_route", r ->
r.path("/payment/get/**").uri("http://localhost:8001")).build();
return routes.build();
}
}
7.2 断言(Predicate)配置
断言:Predicate 是 Spring Cloud Gateway 用来匹配 HTTP 请求的一种方式。Spring Cloud Gateway 提供了多种类型的断言,包括:
- After:请求时间在某个时间之后
- Before:请求时间在某个时间之前
- Cookie:请求中是否包含某个 Cookie
- Header:请求中是否包含某个 Header
- Host:请求的 Host 是否匹配某个正则表达式
- Method:请求的方法是否匹配某个 HTTP 方法
- Path:请求的路径是否匹配某个正则表达式
- Query:请求的查询参数是否匹配某个正则表达式
- RemoteAddr:请求的远程地址是否匹配某个 IP 地址段
- Weight:路由的权重,用于实现 A/B 测试等
官网给我们提供了很多种类型的断言,我们可以根据自己的需求进行选择。
7.3 过滤器(Filter)配置
GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理
过滤器可以在执行方法前和执行方法后进行过滤,所谓的过滤就是可以在请求上加一些操作,例如匹配到路由后可以在请求上添加个请求头,或者参数等等。 Gateway过滤器分为了两种:路由过滤器 和 全局过滤器。
路由过滤器:路由过滤器针对于某一个路由进行使用,其中官网给我们提供了30多种类型的路由过滤器。
常用的路由过滤器:
- AddRequestHeader:添加请求头
spring:
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
filters:
- AddRequestHeader=X-Request-red, blue
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
@GetMapping(value = "/payment/get/{id}")
public CommonResult<Payment> getPaymentById(HttpServletRequest request, @PathVariable("id") Long id) {
String header = request.getHeader("X-Request-red");
System.out.println(header);
Payment payment = paymentMapper.selectById(id);
log.info("*****查询结果:{}", payment);
if (payment != null) {
return new CommonResult(200, "查询成功, 服务端口:" + serverPort, payment);
} else {
return new CommonResult(444, "没有对应记录,查询ID: " + id + ",服务端口:" + serverPort, null);
}
}
- StripPrefix:去掉请求路径前缀
spring:
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
filters:
- StripPrefix=1
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
其中filters的StripPrefix=1表示去掉请求路径的前缀,比如请求路径为/payment/get/1,则去掉前缀后为/get/1,然后再转发到对应的微服务。
全局过滤器:全局的往往是我们经常会用到的,他和路由过滤器区别就是,他是针对于所有路由进行设置的过滤规则,实际开发当中很少会针对于某一个路由使用Filter,大部分都会采用全局过滤器。
7.4 自定义全局过滤器
自定义全局过滤器,我们需要实现GatewayFilter接口,并在配置文件中配置。
//@Order(value = -1) // 设置过滤器的执行顺序 越小越先执行,与实现Ordered接口是一样的效果
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1,获取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> queryParams = request.getQueryParams();
//2,获取参数中的值
String authorize = queryParams.getFirst("authorize");
//3,判断参数值是否等于admin
if("admin".equals(authorize)){
//4,放行
return chain.filter(exchange);
}
//5,拦截
//设置状态码
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
@Override
public int getOrder() {
return -1;
}
}
该过滤器实现了对请求参数中authorize参数进行判断,如果参数值等于admin,则放行,否则拦截。
7.5 过滤器的执行顺序
请求进入网关会碰到三类过滤器: 当前路由的过滤器、DefaultFilter、GlobalFilter
求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器
- 每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前
- GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定
- 路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增
- 当过滤器的order值一样时,会按照 defaultFilter > 路由过滤器>GlobalFilter的顺序执行
8. Gateway 跨域问题
跨域:域名不一致就是跨域,主要包括:
- 域名不同: wwwtaobao.com 和 www.taobao.org 和 wwwjd.com 和 miaoshajd.com
- 域名相同,端口不同: localhost:8080和localhost8081
spring:
application:
name: gateway #服务名称
cloud:
nacos:
discovery:
server-addr: localhost:8848 #nacos地址
gateway:
globalcors:
add-to-simple-url-handler-mapping: true
cors-configurations:
'[/**]': #拦截的请求
allowedOrigins: #允许跨域的请求
- "http://localhost:8080"
allowedMethods: #运行跨域的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" #允许请求中携带的头信息
allowedCredentials: true #是否允许携带cookie
maxAge: 36000 #跨域检测的有效期,单位s