SpringCloud服务网关Gateway

Bertha 。 2022-11-30 13:00 268阅读 0赞

Gateway

pring cloud gateway是spring官方基于Spring 5.0、Spring Boot2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供简单、有效和统一的API路由管理方式,Spring Cloud Gateway作为Spring Cloud生态系统中的网关,目标是替代Netflix Zuul,其不仅提供统一的路由方式,并且还基于Filer链的方式提供了网关基本的功能,例如:安全、监控/埋点、限流等。


工作原理

客户端向Spring Cloud Gateway发出请求。如果网关处理程序映射确定请求与路由匹配,则将其发送到网关Web处理程序。该处理程序通过特定于请求的过滤器链运行请求。筛选器由虚线分隔的原因是,筛选器可以在发送代理请求之前和之后运行逻辑。所有“前置”过滤器逻辑均被执行。然后发出代理请求。发出代理请求后,将运行“后”过滤器逻辑。

在这里插入图片描述

引入POM文件

  1. <!-- 注意,依赖中一定不要包含spring-cloud-starter-web依赖 -->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-gateway</artifactId>
  5. </dependency>
  6. <!-- consul作注册中心 -->
  7. <dependency>
  8. <groupId>org.springframework.cloud</groupId>
  9. <artifactId>spring-cloud-starter-consul-discovery</artifactId>
  10. </dependency>
  11. <!-- 健康监测 -->
  12. <dependency>
  13. <groupId>org.springframework.boot</groupId>
  14. <artifactId>spring-boot-starter-actuator</artifactId>
  15. </dependency>
  16. <!-- hystrix -->
  17. <dependency>
  18. <groupId>org.springframework.cloud</groupId>
  19. <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  20. </dependency>
  21. <!-- redis限流使用 -->
  22. <dependency>
  23. <groupId>org.springframework.boot</groupId>
  24. <artifactId>spring-boot-starter-data-redis</artifactId>
  25. </dependency>

项目目录

在这里插入图片描述

  • 新建Example(8080)和Example2(8081)模拟两个服务。
  • Example的Controller内容:

    @RestController
    public class Controller {

    1. @GetMapping("/a")
    2. public String exampleController1(){
    3. return "example - a";
    4. }
    5. @GetMapping("/aaa")
    6. public String exampleController2(){
    7. return "example - aaa";
    8. }
    9. @GetMapping("/aaa/a")
    10. public String exampleController3(){
    11. return "example - aaa - a";
    12. }

    }

  • Example2的Controller内容:

    @RestController
    public class Example2Controller {

    1. @GetMapping
    2. public String controller(@ModelAttribute Model model) {
    3. try {
    4. Thread.sleep(1000);
    5. } catch (InterruptedException e) {
    6. e.printStackTrace();
    7. }
    8. return "example2 GET " + model.toString();
    9. }
    10. @PostMapping
    11. public String controllerPost(@RequestBody Model model) {
    12. return "example2 POST " + model.toString();
    13. }
    14. @GetMapping("/a")
    15. public String controllerA() {
    16. return "example2 - a";
    17. }
    18. @GetMapping("/a/b")
    19. public String controllerAB() {
    20. return "example2 - a - b";
    21. }
    22. @GetMapping("/b")
    23. public String controllerB() {
    24. return "example2 - b";
    25. }
    26. @GetMapping("/example2/c")
    27. public String controllerC(String name) {
    28. return "example2 - c " + name;
    29. }

    }

  • Example和Example2分别连接到Consul注册中心(省略连接配置文件)结果如图:
    在这里插入图片描述

Gateway(8082)项目

  • 路由:路由是网关最基础的部分,路由信息有一个ID、一个目的URL、一组断言和一组Filter组成。如果断言路由为真,则说明请求的URL和配置匹配。
  • 断言:Java8中的断言函数。Spring Cloud Gateway中的断言函数输入类型是Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的断言函数允许开发者去定义匹配来自于http request中的任何信息,比如请求头和参数等。
  • 过滤器:一个标准的Spring webFilter。Spring cloud gateway中的filter分为两种类型的Filter,分别是Gateway Filter和Global Filter。过滤器Filter将会对请求和响应进行修改处理。
  • 匹配规则:一组断言(predicates)全部满足会进行filters过滤结果转发到uri。

简单路由

  1. spring:
  2. application:
  3. name: gateway
  4. cloud:
  5. consul:
  6. enabled: true
  7. host: localhost
  8. port: 8500
  9. discovery:
  10. health-check-interval: 10s
  11. # 是否检查自己的心跳,本地为false,方便测试
  12. register-health-check: true
  13. instance-id: ${ spring.application.name}:${ server.port}
  14. register: true
  15. prefer-ip-address: true
  16. # health-check-critical-timeout: 30s
  17. gateway:
  18. # loadbalancer:
  19. # # 当找不到对应实例的是否,是否http错误码为404,如果为false,则为503
  20. # use404: true
  21. # discovery:
  22. # locator:
  23. # # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
  24. # enabled: true
  25. routes:
  26. - id: example1
  27. uri: lb://example1
  28. predicates:
  29. - Path=/aaa/**

输入:http://localhost:8082/aaa/a 则路由到:http://localhost:8080/aaa/a,输出:example - aaa - a

截取请求

  1. spring:
  2. cloud:
  3. gateway:
  4. routes:
  5. - id: example1
  6. uri: lb://exampleTwo
  7. predicates:
  8. - Path=/example1/aaa/**
  9. filters:
  10. # 截取路径位数
  11. - StripPrefix=2

输入:http://localhost:8082/example1/aaa/a 则路由到:http://localhost:8081/a,输出:example2 - a

传入指定参数

  1. spring:
  2. cloud:
  3. gateway:
  4. routes:
  5. - id: example2
  6. uri: lb://exampleTwo
  7. predicates:
  8. - Path=/example2
  9. filters:
  10. # 截取路径位数
  11. - StripPrefix=1
  12. # 添加默认参数
  13. - AddRequestParameter=name, Param
  14. - AddRequestParameter=age, 1

输入:http://localhost:8082/example2 则路由到:http://localhost:8081,输出:example2 GET Model{name=‘Param’, age=1}

熔断

  1. spring:
  2. cloud:
  3. gateway:
  4. ### 默认filters,全局生效
  5. default-filters:
  6. - name: defuaultHystrix
  7. args:
  8. name: defaultFallbackcmd
  9. #调用网关/fallback的controller方法
  10. fallbackUri: forward:/fallback
  11. routes:
  12. - id: example2
  13. uri: lb://exampleTwo
  14. predicates:
  15. - Path=/example2
  16. filters:
  17. # 截取路径位数
  18. - StripPrefix=1
  19. # 添加默认参数
  20. - AddRequestParameter=name, Param
  21. - AddRequestParameter=age, 1
  22. ## 熔断
  23. - name: Hystrix
  24. args:
  25. name: fallbackcmd
  26. ### fallback 时调用的方法 http://localhost:8001/fallback
  27. #调用网关/fallback的controller方法
  28. fallbackUri: forward:/fallback
  29. hystrix:
  30. command:
  31. default: # 如果不是默认,可以写成name的值: fallbackcmd
  32. execution:
  33. isolation:
  34. thread:
  35. timeoutInMilliseconds: 1000 #1s

输入:http://localhost:8082/example2 则路由到:http://localhost:8081,由于目标Controller方法睡眠1s所以触发熔断机制,跳转熔断连接:http://localhost:8082/fallback,输出:Hystrix。把熔断时间调大即可正常访问。

限流

确保redis在 3 以上的版本!!!

新建配置类:

  1. @Configuration
  2. public class UriKeyResolver implements KeyResolver {
  3. public Mono<String> resolve(ServerWebExchange exchange) {
  4. return Mono.just(exchange.getRequest().getURI().getPath());
  5. }
  6. }
  7. spring:
  8. cloud:
  9. gateway:
  10. routes:
  11. - id: example2
  12. uri: lb://exampleTwo
  13. predicates:
  14. - Path=/example2
  15. filters:
  16. # 截取路径位数
  17. - StripPrefix=1
  18. # 添加默认参数
  19. - AddRequestParameter=name, Param
  20. - AddRequestParameter=age, 1
  21. ## 限流
  22. - name: RequestRateLimiter
  23. args:
  24. ### 限流过滤器的 Bean 名称
  25. key-resolver: '#{@uriKeyResolver}'
  26. ### 希望允许用户每秒处理多少个请求
  27. redis-rate-limiter.replenishRate: 1
  28. ### 用户允许在一秒钟内完成的最大请求数
  29. redis-rate-limiter.burstCapacity: 3

输入:http://localhost:8082/example2 则路由到:http://localhost:8081,访问正常输出:example2 GET Model{name=‘Param’, age=1}。频繁刷新则触发限流措施,页面显示:429

其它断言写法

  • Header 属性匹配

如果请求头具有名为X-Request-Id其值与\d+正则表达式匹配的标头(即,其值为一个或多个数字),则此路由匹配。

  1. predicates:
  2. - Header=X-Request-Id, \d+
  • Host 属性匹配

如果请求具有这种路由匹配Host用的头值www.somehost.org或beta.somehost.org或www.anotherhost.org。

  1. predicates:
  2. - Host=**.somehost.org,**.anotherhost.org
  • Method 属性匹配

匹配GET请求

  1. predicates:
  2. - Method=GET
  • 路由匹配

根据路由策略匹配

  1. predicates:
  2. - Path=/red/{ segment},/blue/{ segment}
  • 根据参数匹配

如果请求包含green查询参数,则匹配。

  1. predicates:
  2. - Query=green

如果请求包含red开头(任意长度)且gree开头(长度为5)参数,则匹配。

  1. predicates:
  2. - Query=red.*, gree.
  • 设置排序

匹配顺序按order指定的升序(值小优先)来依次匹配。

  1. - id: example2
  2. uri: lb://exampleTwo
  3. order: 100
  4. - id: example1
  5. uri: lb://exampleTwo
  6. order: 50

先匹配example1,如果不满足再匹配example2。

代码实现Filter

实现自定义Filter

  1. public class HeaderFilter implements GatewayFilter {
  2. //Mono: 包含0个或1个元素的异步序列
  3. //Flux: 包含0个或多个元素的异步序列
  4. @Override
  5. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  6. //向请求中添加指定的header
  7. ServerHttpRequest changeRequest = exchange.getRequest()
  8. .mutate()
  9. .header("X-Request-red", "blue")
  10. .build();
  11. //将变更过的请求写入到exchange
  12. ServerWebExchange webExchange = exchange.mutate()
  13. .request(changeRequest)
  14. .build();
  15. //将变更过的exchange向下传递
  16. return chain.filter(webExchange);
  17. }
  18. }

注入自定义FilterBean

  1. @Bean
  2. public RouteLocator someRouteLocator(RouteLocatorBuilder builder) {
  3. return builder.routes()
  4. .route(ps -> ps.path("/**")
  5. .filters(f -> f.filter(new HeaderFilter()))
  6. .uri("http://localhost:8082")
  7. .id("custom_filter_route"))
  8. .build();
  9. }
  • 全局Filter
    Global Filter不需要在任何具体路由规则中进行注册,只需在类上添加@Componment注解并实现GlobalFilter即可。

Filter工作原理

自定义三个Filter

  1. public class OneFilter implements GatewayFilter {
  2. @Override
  3. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  4. System.out.println("pre-1");
  5. return chain.filter(exchange).then(
  6. Mono.fromRunnable(() -> {
  7. System.out.println("post-1");
  8. })
  9. );
  10. }
  11. }
  12. public class TwoFilter implements GatewayFilter {
  13. @Override
  14. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  15. System.out.println("pre-2");
  16. return chain.filter(exchange).then(
  17. Mono.fromRunnable(() -> {
  18. System.out.println("post-2");
  19. })
  20. );
  21. }
  22. }
  23. public class ThreeFilter implements GatewayFilter {
  24. @Override
  25. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  26. System.out.println("pre-3");
  27. return chain.filter(exchange).then(
  28. Mono.fromRunnable(() -> {
  29. System.out.println("post-3");
  30. })
  31. );
  32. }
  33. }

注入自定义FilterBean

  1. @Bean
  2. public RouteLocator someRouteLocator(RouteLocatorBuilder builder) {
  3. return builder.routes()
  4. .route(ps -> ps.path("/**")
  5. .filters(f -> f.filter(new OneFilter())
  6. .filter(new TwoFilter())
  7. .filter(new ThreeFilter()))
  8. .uri("http://localhost:8082")
  9. .id("custom_filter_route"))
  10. .build();
  11. }

根据注入顺序先执行OneFilter->TwoFilter->ThreeFilter

控制台输出:

  1. pre-1
  2. pre-2
  3. pre-3
  4. post-3
  5. post-2
  6. post-1

执行顺序
在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,268人围观)

还没有评论,来说两句吧...

相关阅读