Spring Cloud Gateway

zuul终究还是被时代淘汰了,spring基本上也逐渐放弃了Netflix平台,自己搞起了gateway。这不得不聊起一个人 Spencer Gibb,他是zuul的核心开发,带领一群有志青年,放弃zuul,转战spring cloud gateway。

应用搭建

其maven依赖如下:

xml 复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

之后,只需要写个简单的spring boot程序就可以了,与zuul不同的是,gateway没有@Enable开头的开关:

java 复制代码
@SpringBootApplication
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

这就是gateway与zuul设计哲学的不同。

网关配置

光完成上述代码肯定不够,因为没有配置转发。以下是配置文件的一个例子:

yml 复制代码
server:
  port: 80 # 网关端口

spring:
  cloud:
    gateway:
      routes:
        - id: user_route
          # 直接写死目标服务的 IP 和端口
          uri: http://127.0.0.1:8001
          predicates:
            - Path=/user/**

之后就可以正常转发了。

谓词配置

配置中的predicates是gateway的谓词,这部分可谓非常复杂了。上述例子里用的是路径谓词。此外我还整理了其他比较好用的谓词.

谓词名称 用途 典型场景
Path 匹配请求路径 /api/ 转发给某个服务
Query 匹配请求参数 根据 URL 中的参数(如版本号)分流
Header 匹配请求头 根据 User-Agent 或自定义 Header 鉴权
Method 匹配请求方法 只允许 GET 或 POST 请求通过
Cookie 匹配 Cookie 针对特定用户群体的灰度发布
Host 匹配域名 基于域名的路由(如 *.abc.com
RemoteAddr 匹配客户端 IP 黑白名单、IP 限流
After/Before 匹配时间 活动期间开启特定页面,或维护窗口

过滤器

除了谓词以外,gateway还提供了过滤器配置,以达到更精致的网关控制。以下是常见的过滤器:

分类 过滤器名称 (Filter Name) 核心作用
请求处理 AddRequestHeader 给请求头添加自定义信息
AddRequestParameter 给请求添加参数
RewritePath 重写请求路径(最常用)
StripPrefix 截断请求路径前缀
RequestRateLimiter 请求限流(令牌桶算法)
响应处理 AddResponseHeader 给响应头添加信息
DedupeResponseHeader 去除响应头中重复的值
SetStatus 修改返回的状态码
路由增强 Hystrix 熔断保护(旧版)
RequestSize 限制请求包大小
Retry 失败自动重试

转发实现

gateway是怎么转发的?gateway是基于WebFlux技术的。gateway写了一个RoutePredicateHandlerMapping,该类实现了HandlerMapping接口,所以充当了传统servlet里控制器的角色。核心方法在lookupRoute里。在追踪gateway源码时我们可以记录一下堆栈的变化。

  1. 线程Thread[reactor-http-nio-2,5,main]

at org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping.lookupRoute(RoutePredicateHandlerMapping.java:128)

at org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping.getHandlerInternal(RoutePredicateHandlerMapping.java:87)

at org.springframework.web.reactive.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:181)

  1. 线程Thread[reactor-http-nio-2,5,main]

at org.springframework.cloud.gateway.handler.FilteringWebHandler.handle(FilteringWebHandler.java:77)

at org.springframework.web.reactive.result.SimpleHandlerAdapter.handle(SimpleHandlerAdapter.java:45)

at org.springframework.web.reactive.DispatcherHandler.invokeHandler(DispatcherHandler.java:161)

  1. 线程Thread[reactor-http-nio-2,5,main]

at org.springframework.cloud.gateway.filter.NettyRoutingFilter.filter(NettyRoutingFilter.java:104)

at org.springframework.cloud.gateway.handler.FilteringWebHandler$GatewayFilterAdapter.filter(FilteringWebHandler.java:138)

at org.springframework.cloud.gateway.filter.OrderedGatewayFilter.filter(OrderedGatewayFilter.java:44)

NettyRoutingFilter这个类里终于找到了转发的代码了,我只贴一行代码,不过这行代码可够长的了:

java 复制代码
Flux<HttpClientResponse> responseFlux = this.httpClient.headers(headers -> {
			headers.add(httpHeaders);
			if (preserveHost) {
				String host = request.getHeaders().getFirst(HttpHeaders.HOST);
				headers.add(HttpHeaders.HOST, host);
			}
			else {
				// let Netty set it based on hostname
				headers.remove(HttpHeaders.HOST);
			}
		}).request(method).uri(url).send((req, nettyOutbound) -> {
			if (log.isTraceEnabled()) {
				nettyOutbound.withConnection(connection -> log.trace(
						"outbound route: " + connection.channel().id().asShortText()
								+ ", inbound: " + exchange.getLogPrefix()));
			}
			return nettyOutbound.send(request.getBody()
					.map(dataBuffer -> ((NettyDataBuffer) dataBuffer).getNativeBuffer()));
		}).responseConnection((res, connection) -> {

			// 省略很多很多代码。。。。。。。

			return Mono.just(res);
		});
相关推荐
考虑考虑2 小时前
JDK25模块导入声明
java·后端·java ee
_小马快跑_3 小时前
Java 的 8 大基本数据类型:为何是不可或缺的设计?
java
Re_zero6 小时前
线上日志被清空?这段仅10行的 IO 代码里竟然藏着3个毒瘤
java·后端
洋洋技术笔记6 小时前
Spring Boot条件注解详解
java·spring boot
程序员清风1 天前
程序员兼职必看:靠谱软件外包平台挑选指南与避坑清单!
java·后端·面试
皮皮林5511 天前
利用闲置 Mac 从零部署 OpenClaw 教程 !
java
NE_STOP1 天前
springMVC-HTTP消息转换器与文件上传、下载、异常处理
spring
华仔啊1 天前
挖到了 1 个 Java 小特性:var,用完就回不去了
java·后端
SimonKing1 天前
SpringBoot整合秘笈:让Mybatis用上Calcite,实现统一SQL查询
java·后端·程序员
日月云棠2 天前
各版本JDK对比:JDK 25 特性详解
java