1. 什么是Spring Cloud Gateway

网关作为流量的入口,常用的功能包括路由转发,权限校验,限流等。

Spring Cloud Gateway 是Spring Cloud官方推出的第二代网关框架,定位于取代 Netflix Zuul。相比 Zuul 来说,Spring Cloud Gateway 提供更优秀的性能,更强大的有功能。

Spring Cloud Gateway 是由 WebFlux + Netty + Reactor 实现的响应式的 API 网关。它不能在传统的 servlet 容器中工作,也不能构建成 war 包。

Spring Cloud Gateway 旨在为微服务架构提供一种简单且有效的 API 路由的管理方式,并基于 Filter 的方式提供网关的基本功能,例如说安全认证、监控、限流等等。

官网文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories

1.1 核心概念

  • 路由(route)

路由是网关中最基础的部分,路由信息包括一个ID、一个目的URI、一组断言工厂、一组Filter组成。如果断言为真,则说明请求的URL和配置的路由匹配。

  • 断言(predicates)

Java8中的断言函数,SpringCloud Gateway中的断言函数类型是Spring5.0框架中的ServerWebExchange。断言函数允许开发者去定义匹配Http request中的任何信息,比如请求头和参数等。

  • 过滤器(Filter)

SpringCloud Gateway中的filter分为Gateway FilIer和Global Filter。Filter可以对请求和响应进行处理。

1.2 工作原理

Spring Cloud Gateway 的工作原理跟 Zuul 的差不多,最大的区别就是 Gateway 的 Filter 只有 pre 和 post 两种。

  客户端向 Spring Cloud Gateway 发出请求,如果请求与网关程序定义的路由匹配,则该请求就会被发送到网关 Web 处理程序,此时处理程序运行特定的请求过滤器链。

  过滤器之间用虚线分开的原因是过滤器可能会在发送代理请求的前后执行逻辑。所有 pre 过滤器逻辑先执行,然后执行代理请求;代理请求完成后,执行 post 过滤器逻辑。

2. Spring Cloud Gateway快速开始

**2.1 环境搭建

  1. 引入依赖**
<!-- gateway网关 -->
<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-webmvc的依赖冲突,需要排除spring-webmvc

2) 编写yml配置文件

server:port: 8888
spring:application:name: mall-gateway#配置nacos注册中心地址cloud:nacos:discovery:server-addr: 127.0.0.1:8848gateway:discovery:locator:# 默认为false,设为true开启通过微服务创建路由的功能,即可以通过微服务名访问服务# http://localhost:8888/mall-order/order/findOrderByUserId/1enabled: true# 是否开启网关    enabled: true

3)测试

2.2 路由断言工厂(Route Predicate Factories)配置

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories

网关启动日志:

2.2.1 时间匹配

可以用在限时抢购的一些场景中。

spring:cloud:gateway:#设置路由:路由id、路由到微服务的uri、断言routes:- id: order_route  #路由ID,全局唯一uri: http://localhost:8020  #目标微服务的请求地址和端口predicates:# 测试:http://localhost:8888/order/findOrderByUserId/1# 匹配在指定的日期时间之后发生的请求  入参是ZonedDateTime类型- After=2021-01-31T22:22:07.783+08:00[Asia/Shanghai]

获取ZonedDateTime类型的指定日期时间

ZonedDateTime zonedDateTime = ZonedDateTime.now();//默认时区
// 用指定时区获取当前时间
ZonedDateTime zonedDateTime2 = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));

设置时间之前发起请求:

超过设置时间之后再次请求:

2.2.2 Cookie匹配

spring:cloud:gateway:#设置路由:路由id、路由到微服务的uri、断言routes:- id: order_route  #路由ID,全局唯一uri: http://localhost:8020  #目标微服务的请求地址和端口predicates:# Cookie匹配- Cookie=username, fox

postman测试

curl测试

2.2.3 Header匹配

spring:cloud:gateway:#设置路由:路由id、路由到微服务的uri、断言routes:- id: order_route  #路由ID,全局唯一uri: http://localhost:8020  #目标微服务的请求地址和端口predicates:# Header匹配  请求中带有请求头名为 x-request-id,其值与 \d+ 正则表达式匹配#- Header=X-Request-Id, \d+

测试

2.2.4 路径匹配

spring:cloud:gateway:#设置路由:路由id、路由到微服务的uri、断言routes:- id: order_route  #路由ID,全局唯一uri: http://localhost:8020  #目标微服务的请求地址和端口predicates:# 测试:http://localhost:8888/order/findOrderByUserId/1- Path=/order/**   #Path路径匹配

2.2.5 自定义路由断言工厂

  自定义路由断言工厂需要继承 AbstractRoutePredicateFactory 类,重写 apply 方法的逻辑。在 apply 方法中可以通过 exchange.getRequest() 拿到 ServerHttpRequest 对象,从而可以获取到请求的参数、请求方式、请求头等信息。

注意: 命名需要以 RoutePredicateFactory 结尾

@Component
@Slf4j
public class CheckAuthRoutePredicateFactory extends AbstractRoutePredicateFactory<CheckAuthRoutePredicateFactory.Config> {public CheckAuthRoutePredicateFactory() {super(Config.class);}@Overridepublic Predicate<ServerWebExchange> apply(Config config) {return new GatewayPredicate() {@Overridepublic boolean test(ServerWebExchange serverWebExchange) {log.info("调用CheckAuthRoutePredicateFactory" + config.getName());if(config.getName().equals("fox")){return true;}return false;}};}/*** 快捷配置* @return*/@Overridepublic List<String> shortcutFieldOrder() {return Collections.singletonList("name");}public static class Config {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}}
}

yml中配置

spring:cloud:gateway:#设置路由:路由id、路由到微服务的uri、断言routes:- id: order_route  #路由ID,全局唯一uri: http://localhost:8020  #目标微服务的请求地址和端口predicates:# 测试:http://localhost:8888/order/findOrderByUserId/1- Path=/order/**   #Path路径匹配#自定义CheckAuth断言工厂
#        - name: CheckAuth
#          args:
#            name: fox- CheckAuth=fox

2.3 过滤器工厂( GatewayFilter Factories)配置

  SpringCloudGateway 内置了很多的过滤器工厂,我们通过一些过滤器工厂可以进行一些业务逻辑处理器,比如添加剔除响应头,添加去除参数等

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories

2.3.1 添加请求头

spring:cloud:gateway:#设置路由:路由id、路由到微服务的uri、断言routes:- id: order_route  #路由ID,全局唯一uri: http://localhost:8020  #目标微服务的请求地址和端口#配置过滤器工厂filters:- AddRequestHeader=X-Request-color, red  #添加请求头

测试http://localhost:8888/order/testgateway

@GetMapping("/testgateway")
public String testGateway(HttpServletRequest request) throws Exception {log.info("gateWay获取请求头X-Request-color:"+request.getHeader("X-Request-color"));return "success";
}
@GetMapping("/testgateway2")
public String testGateway(@RequestHeader("X-Request-color") String color) throws Exception {log.info("gateWay获取请求头X-Request-color:"+color);return "success";
}

2.3.2 添加请求参数

spring:cloud:gateway:#设置路由:路由id、路由到微服务的uri、断言routes:- id: order_route  #路由ID,全局唯一uri: http://localhost:8020  #目标微服务的请求地址和端口#配置过滤器工厂filters:- AddRequestParameter=color, blue  # 添加请求参数

测试http://localhost:8888/order/testgateway3

@GetMapping("/testgateway3")
public String testGateway3(@RequestParam("color") String color) throws Exception {log.info("gateWay获取请求参数color:"+color);return "success";
}


2.3.3 为匹配的路由统一添加前缀

spring:cloud:gateway:#设置路由:路由id、路由到微服务的uri、断言routes:- id: order_route  #路由ID,全局唯一uri: http://localhost:8020  #目标微服务的请求地址和端口#配置过滤器工厂filters:- PrefixPath=/mall-order  # 添加前缀 对应微服务需要配置context-path

mall-order中需要配置

server:servlet:context-path: /mall-order

测试:http://localhost:8888/order/findOrderByUserId/1 ====》 http://localhost:8020/mall-order/order/findOrderByUserId/1

2.3.4 重定向操作

spring:cloud:gateway:#设置路由:路由id、路由到微服务的uri、断言routes:- id: order_route  #路由ID,全局唯一uri: http://localhost:8020  #目标微服务的请求地址和端口#配置过滤器工厂filters:- RedirectTo=302, https://www.baidu.com/  #重定向到百度

测试:http://localhost:8888/order/findOrderByUserId/1

2.3.5 自定义过滤器工厂

  继承AbstractNameValueGatewayFilterFactory且我们的自定义名称必须要以GatewayFilterFactory结尾并交给spring管理。

@Component
@Slf4j
public class CheckAuthGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {@Overridepublic GatewayFilter apply(NameValueConfig config) {return (exchange, chain) -> {log.info("调用CheckAuthGatewayFilterFactory==="+ config.getName() + ":" + config.getValue());return chain.filter(exchange);};}
}

配置自定义的过滤器工厂

spring:cloud:gateway:#设置路由:路由id、路由到微服务的uri、断言routes:- id: order_route  #路由ID,全局唯一uri: http://localhost:8020  #目标微服务的请求地址和端口#配置过滤器工厂filters:- CheckAuth=fox,男

测试

2.4 全局过滤器(Global Filters)配置

GlobalFilter 接口和 GatewayFilter 有一样的接口定义,只不过, GlobalFilter 会作用于所有路由。

官方声明:GlobalFilter的接口定义以及用法在未来的版本可能会发生变化。

2.4.1 LoadBalancerClientFilter

  LoadBalancerClientFilter 会查看exchange的属性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的值(一个URI),如果该值的scheme是 lb,比如:lb://myservice ,它将会使用Spring Cloud的LoadBalancerClient 来将 myservice 解析成实际的host和port,并替换掉 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的内容。

  其实就是用来整合负载均衡器Ribbon的

spring:cloud:gateway:routes:- id: order_routeuri: lb://mall-orderpredicates:- Path=/order/**

2.4.2 自定义全局过滤器

@Component
@Order(-1)
@Slf4j
public class CheckAuthFilter implements GlobalFilter {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//校验请求头中的tokenList<String> token = exchange.getRequest().getHeaders().get("token");log.info("token:"+ token);if (token.isEmpty()){return null;}return chain.filter(exchange);}
}@Component
public class CheckIPFilter implements GlobalFilter, Ordered {@Overridepublic int getOrder() {return 0;}@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {HttpHeaders headers = exchange.getRequest().getHeaders();//模拟对 IP 的访问限制,即不在 IP 白名单中就不能调用的需求if (getIp(headers).equals("127.0.0.1")) {return null;}return chain.filter(exchange);}private String getIp(HttpHeaders headers) {return headers.getHost().getHostName();}
}

2.5 Gateway跨域配置(CORS Configuration)

通过yml配置的方式

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#cors-configuration

spring:cloud:gateway:globalcors:cors-configurations:'[/**]':allowedOrigins: "*"allowedMethods:- GET- POST- DELETE- PUT- OPTION

通过java配置的方式

@Configuration
public class CorsConfig {@Beanpublic CorsWebFilter corsFilter() {CorsConfiguration config = new CorsConfiguration();config.addAllowedMethod("*");config.addAllowedOrigin("*");config.addAllowedHeader("*");UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());source.registerCorsConfiguration("/**", config);return new CorsWebFilter(source);}
}

2.6 gateway整合sentinel限流

https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81
从 1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:

  • route 维度:即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeId
  • 自定义 API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组

2.6.1 快速开始
使用时需引入依赖:

<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-spring-cloud-gateway-adapter</artifactId><version>x.y.z</version>
</dependency>`在这里插入代码片`

接入sentinel dashboard,添加yml配置

spring:application:name: mall-gateway-sentinel-demo#配置nacos注册中心地址cloud:nacos:discovery:server-addr: 127.0.0.1:8848sentinel:transport:# 添加sentinel的控制台地址dashboard: 127.0.0.1:8080

使用时只需注入对应的 SentinelGatewayFilter 实例以及 SentinelGatewayBlockExceptionHandler 实例即可

@Configuration
public class GatewayConfiguration {private final List<ViewResolver> viewResolvers;private final ServerCodecConfigurer serverCodecConfigurer;public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,ServerCodecConfigurer serverCodecConfigurer) {this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);this.serverCodecConfigurer = serverCodecConfigurer;}/*** 限流异常处理器* @return*/@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {// Register the block exception handler for Spring Cloud Gateway.return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);}/*** 限流过滤器* @return*/@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public GlobalFilter sentinelGatewayFilter() {return new SentinelGatewayFilter();}}

用户可以通过 GatewayRuleManager.loadRules(rules) 手动加载网关规则GatewayConfiguration中添加

    @PostConstructpublic void doInit() {//初始化自定义的APIinitCustomizedApis();//初始化网关限流规则initGatewayRules();//自定义限流异常处理器initBlockRequestHandler();}private void initCustomizedApis() {Set<ApiDefinition> definitions = new HashSet<>();ApiDefinition api = new ApiDefinition("user_service_api").setPredicateItems(new HashSet<ApiPredicateItem>() {{add(new ApiPathPredicateItem().setPattern("/user/**").setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));}});definitions.add(api);GatewayApiDefinitionManager.loadApiDefinitions(definitions);}private void initGatewayRules() {Set<GatewayFlowRule> rules = new HashSet<>();//resource:资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称。//count:限流阈值//intervalSec:统计时间窗口,单位是秒,默认是 1 秒。rules.add(new GatewayFlowRule("order_route").setCount(2).setIntervalSec(1));rules.add(new GatewayFlowRule("user_service_api").setCount(2).setIntervalSec(1));// 加载网关规则GatewayRuleManager.loadRules(rules);}private void initBlockRequestHandler() {BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {@Overridepublic Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable t) {HashMap<String, String> result = new HashMap<>();result.put("code",String.valueOf(HttpStatus.TOO_MANY_REQUESTS.value()));result.put("msg", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(result));}};//设置自定义异常处理器GatewayCallbackManager.setBlockHandler(blockRequestHandler);}

2.6.2 网关流控控制台

Sentinel 1.6.3 引入了网关流控控制台的支持,用户可以直接在 Sentinel 控制台上查看 API Gateway 实时的 route 和自定义 API 分组监控,管理网关规则和 API 分组配置。

在 API Gateway 端,用户只需要在原有启动参数的基础上添加如下启动参数即可标记应用为 API Gateway 类型:

# 注:通过 Spring Cloud Alibaba Sentinel 自动接入的 API Gateway 整合则无需此参数
-Dcsp.sentinel.app.type=1

2.6.3 网关流控实现原理

2.7 网关高可用

为了保证 Gateway 的高可用性,可以同时启动多个 Gateway 实例进行负载,在 Gateway 的上游使用 Nginx 或者 F5 进行负载转发以达到高可用。

微服务网关Gateway实战相关推荐

  1. SpringCloud 微服务网关Gateway 动态路由配置

    概述:在上一章节<SpringCloud 微服务网关Gateway介绍及简单路由配置>中我们讲述了Gateway的最简单的路由配置方式.但是其中比较明显的问题就是我们在配置路由服务的地址时 ...

  2. Spring Cloud之(十八)微服务网关GateWay

    十八.微服务网关GateWay Zuul 1.x 是一个基于阻塞 IO 的 API Gateway 以及 Servlet:直到 2018 年 5 月,Zuul 2.x(基于Netty,也是非阻塞的,支 ...

  3. SpringCloud—— 微服务网关GateWay

    目录 1.GateWay网关概述 1.1.什么是GateWay? 1.2.为什么要使用微服务网关? 1.3.Zuul与GateWay网关的区别? 2.快速入门 2.1.创建项目 2.2.配置yml文件 ...

  4. 微服务网关Gateway

    使用场景 不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题: 客户端会多次请求不同的微服务,增加了客户端 ...

  5. SpringCloud 微服务网关Gateway介绍及简单路由配置

    概述:什么是微服务网关?为了解决用户客户端在调用微服务系统中的多个消费者工程接口时,需要维护非常多的消费者应用接口地址等信息,以及可能存在不同应用见的调用跨域等问题,微服务网关组件随即出现.网关作为用 ...

  6. 微服务网关GateWay 过滤+路由+限流

    文章目录 1 微服务网关概述 2 微服务网关微服务搭建 3 微服务网关跨域 4 微服务网关过滤器 5 微服务网关限流 5.1 思路分析 5.2 令牌桶算法 5.3 网关限流代码实现 1 微服务网关概述 ...

  7. SpringCloud Alibaba 微服务 — 微服务网关 Gateway

    一.Spring Cloud Gateway 简介 Spring Cloud Gateway 是 Spring 官方基于 Spring 5.x.Spring Boot 2.x.Spring WebFl ...

  8. 微服务网关Gateway(七)

    前言 zuul目前已经出现了分歧,zuul 升级到 Zuul2的时候出现了内部分歧,并且导致Zuul的核心人员的离职,导致Zuul2一直跳票,等了两年,目前造成的局面是Zuul已经没人维护,Zuul2 ...

  9. Spring Cloud 微服务网关Gateway组件

    一.网关介绍 大家都知道在微服务架构中,一个系统会被拆分为多个微服务,那么作为客户端如何去调用这么多的微服务呢?如果没有网关的存在,我们只能在客户端记录每个微服务的地址,然后分别去用. 这样的架构会存 ...

最新文章

  1. [原]missing #39;;#39; before #39;namesapce#39;错误的解决
  2. maven 工程启动找不到 Spring ContextLoaderListener 的解决办法
  3. 神策数据出席 TIC 2018 大会,共同赋能大数据时代
  4. jquery 按钮效果 正常、移上、按下
  5. 他被女朋友拉黑后,写了个“舔狗”必备神器
  6. eclipse插件开发:自定义导航器中的拖拽定义
  7. python pyquery倒数第二个节点之前的节点_Python中PyQuery库的使用总结
  8. 读贾志鹏线性筛有感 (莫比乌斯函数的应用)
  9. c#开发大全、系列文章、精品教程
  10. C# Log4Net简单使用方法
  11. 无锡鼋头渚樱花颜色单调
  12. 文件恢复原理Linux文件恢复工具-foremostextundelete
  13. Linux压力测试工具
  14. YOLOv5数据集标注工具
  15. 数据迁移 java_数据迁移的成功策略
  16. java 内存使用过高_Java服务器内存和CPU占用过高的原因
  17. 视频接口:DP接口和HDMI接口介绍,看完你就懂了
  18. 都2022年了,这11个Java开发工具你还不知道?
  19. RxHttp 全网Http缓存最优解,完整PDF
  20. 六月集训(第17天) —— 广度优先搜索

热门文章

  1. 中国平行进口汽车行业发展方向及未来发展趋势展望报告2022-2028年
  2. 灰色预测模型python_python实现灰色预测模型(GM11)——以预测股票收盘价为例
  3. 合肥市驾驶证,行驶证期满换证指南
  4. python读取txt每一行按照正则匹配hon-正则表达式使用python从文件中过滤和删除特定的多行文本...
  5. 0507 #2 NYIST 括号配对问题
  6. layout_constraintWidth_percent in java
  7. 关于弹出消息窗口的自动关闭
  8. NEO源码分析之UTXO全局资产
  9. 康托展开式在排列组合的英勇_英勇的射击有一个根本缺陷
  10. ROMP:Monocular, One-stage, Regression of Multiple 3D People