SpringCloud-Gateway网关学习和实战

SpringCloud-Gateway网关学习和实战

1.Gateway概述

1.1 什么是Gateway

上一代zuul 1.x官网

Gateway官网

Cloud全家桶中有个很重要的组件就是网关,在1.x版本中都是采用的Zuul网关;

但在2.x版本中,zuul的升级一直跳票,SpringCloud最后自己研发了一个网关替代Zuul,那就是SpringCloud Gateway—句话:gateway是原zuul1.x版的替代

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fuLsvolV-1653224498500)( https://com-qianyue-img.oss-cn-hangzhou.aliyuncs.com/img/54b61d819aa1630bc61732de340b55b4.png)]

Gateway是在Spring生态系统之上构建的API网关服务,由 WebFlux + Netty + Reactor 实现的响应式的 API 网关。它不能在传统的 servlet 容器中

工作,也不能构建成 war 包

1.2 Gateway可以干什么

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

1.3 Gateway在微服务架构中的位置

SpringCloud-Gateway网关学习和实战_第1张图片

1.4 Gateway核心组件

三大核心概念

Route(路由) - 路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如断言为true则匹配该路由;
Predicate(断言) - 参考的是Java8的java.util.function.Predicate,开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由;
Filter(过滤) - 指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改(此过滤非SpringMVC的过滤器)。

1.5 Gateway的基本原理

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

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

SpringCloud-Gateway网关学习和实战_第2张图片

2.Gateway实战

2.1 环境搭建

1.新建网关模块,添加依赖

    <dependencies>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-gatewayartifactId>
        dependency>

        
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
        dependency>

        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <version>1.18.10version>
        dependency>
    dependencies>

2.yaml配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      enabled: true #是否开启网关

3.添加主启动类

@SpringBootApplication
public class MallGatewayApplication8888 {

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

2.2 实战操作

2.3.1 通过微服务名称调用

(1).配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true  #为true代表 我们可以通过微服务名称调用,不推荐
      enabled: true #是否开启网关

(2).测试 访问http://localhost:8888/mall-order/order/findOrderByUserId/1,这种方式太low了我们是不希望微服务名称暴漏的。

SpringCloud-Gateway网关学习和实战_第3张图片

2.3.2 路由加断言

Spring Cloud Gateway包括许多内置的Route Predicate工厂。所有这些Predicate都与HTTP请求的不同属性匹配。多个RoutePredicate工厂可以进行组合。Spring Cloud Gateway创建Route 对象时,使用RoutePredicateFactory 创建 Predicate对象,Predicate 对象可以赋值给Route。Spring Cloud Gateway包含许多内置的Route Predicate Factories。所有这些谓词都匹配HTTP请求的不同属性。多种谓词工厂可以组合,并通过逻辑and。

常用的Route Predicate Factory

The After Route Predicate Factory
The Before Route Predicate Factory
The Between Route Predicate Factory
The Cookie Route Predicate Factory
The Header Route Predicate Factory
The Host Route Predicate Factory
The Method Route Predicate Factory
The Path Route Predicate Factory
The Query Route Predicate Factory
The RemoteAddr Route Predicate Factory
The weight Route Predicate Factory

下边以其中几个常用的断言演示下效果

1.Path断言

(1)配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true  #为true代表 我们可以通过微服务名称调用,不推荐
      enabled: true #是否开启网关
      routes:
      - id: order_route #路由ID,全局唯一
        #uri: http://localhost:8020 #目标微服务的请求地址和端口  我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
        uri: lb://mall-order
        predicates:
        - Path=/order/**

(2)测试,访问http://localhost:8888/order/findOrderByUserId/1

SpringCloud-Gateway网关学习和实战_第4张图片

2.After Route Predicate

指定时间后才可以访问接口,否则报404错误

(1)配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true  #为true代表 我们可以通过微服务名称调用,不推荐
      enabled: true #是否开启网关
      routes:
      - id: order_route #路由ID,全局唯一
        #uri: http://localhost:8020 #目标微服务的请求地址和端口  我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
        uri: lb://mall-order
        predicates:
        - Path=/order/**
        - After=2022-05-22T16:35:05.794+08:00[Asia/Shanghai] #指定时间后才可以访问

这里的时间可以用以下方式获取

        ZonedDateTime now = ZonedDateTime.now();
        System.out.println(now);

(2)两个时间点访问http://localhost:8888/order/findOrderByUserId/1

16:34分效果

SpringCloud-Gateway网关学习和实战_第5张图片

16:35分效果

SpringCloud-Gateway网关学习和实战_第6张图片

before\betwwen和after用法一样,这里不做演示

3 Cookie Route Predicate

Cookie必须带有指定的Cookie才可以访问

(1)配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true  #为true代表 我们可以通过微服务名称调用,不推荐
      enabled: true #是否开启网关
      routes:
      - id: order_route #路由ID,全局唯一
        #uri: http://localhost:8020 #目标微服务的请求地址和端口  我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
        uri: lb://mall-order
        predicates:
        - Path=/order/**
        - Cookie=username,qianyue  #key=username value=qianyue

(2)带Cookie和不带Cookie分别访问http://localhost:8888/order/findOrderByUserId/1

不带Cookie ,访问不成功

SpringCloud-Gateway网关学习和实战_第7张图片

携带Cookie,访问成功

SpringCloud-Gateway网关学习和实战_第8张图片

4 Header Route Predicate

请求头断言,必须带有指定的请求头才成功

(1)配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true  #为true代表 我们可以通过微服务名称调用,不推荐
      enabled: true #是否开启网关
      routes:
      - id: order_route #路由ID,全局唯一
        #uri: http://localhost:8020 #目标微服务的请求地址和端口  我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
        uri: lb://mall-order
        predicates:
        - Path=/order/**
        - Header=X-Request-Id,\d+  #表示key为X-Request-Id, value必须为整数

(2)测试 带请求头和不带请求头分别访问http://localhost:8888/order/findOrderByUserId/1

不带请求头 访问失败

SpringCloud-Gateway网关学习和实战_第9张图片

携带请求头 访问成功

SpringCloud-Gateway网关学习和实战_第10张图片

5 自定义断言工厂

创建CheckAuthRoutePredicateFactory类实现AbstractRoutePredicateFactory

/**
 * 自定义断言工厂 处理我们的断言逻辑
 * @author wcy
 */
@Component
@Slf4j
public class CheckAuthRoutePredicateFactory extends AbstractRoutePredicateFactory<CheckAuthRoutePredicateFactory.Config> {

    public CheckAuthRoutePredicateFactory() {
        super(Config.class);
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {

            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                log.info("调用CheckAuthRoutePredicateFactory" + config.getName());
                if("auth".equals(config.getName())){
                    return true;
                }
                return false;
            }
        };
    }

    /**
     * 快捷配置
     * @return
     */
    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("name");
    }

    /**
     * 需要定义一个内部类,该类用于封装application.yml中的配置
     */
    public static class Config {

        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

2.yaml配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true  #为true代表 我们可以通过微服务名称调用,不推荐
      enabled: true #是否开启网关
      routes:
      - id: order_route #路由ID,全局唯一
        #uri: http://localhost:8020 #目标微服务的请求地址和端口  我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
        uri: lb://mall-order
        predicates:
        - Path=/order/**
        #- After=2022-05-22T16:35:05.794+08:00[Asia/Shanghai] #指定时间后才可以访问
        #- Cookie=username,qianyue  #key=username value=qianyue
        #- Header=X-Request-Id,\d+  #表示key为X-Request-Id, value必须为整数
        - CheckAuth=auth

3.测试 只有配置CheckAuth=auth才可以访问通过 否则报404

SpringCloud-Gateway网关学习和实战_第11张图片

2.3.3 路由加断言加过滤器

路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用。Spring Cloud Gateway内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生。

过滤器的声明尤其有

pre:代理请求方法执行前执行

post:代理请求方法执行后执行

过滤器有两种GatewayFilter 和GlobalFilter

GatewayFilter

1 添加请求头/请求参数请求服务接口

(1)在order服务添加对应接口

/**
 * @author wcy
 */
@RestController
@RequestMapping("/order")
@Slf4j
public class GatewayController {

    /**
     * 测试gateway
     * @param request
     * @return
     * @throws Exception
     */
    @GetMapping("/testgateway")
    public String testGateway(HttpServletRequest request) throws Exception {
        log.info("gateWay获取请求头X-Request-color:"
                +request.getHeader("X-Request-color"));

        String color = request.getParameter("color");
        log.info("gateWay获取请求参数color:"
                +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";
    }
    @GetMapping("/testgateway3")
    public String testGateway3(@RequestParam("color") String color) throws Exception {
        log.info("gateWay获取请求参数color:"+color);
        return "success";
    }

}

(2)在gateway网关层添加配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true  #为true代表 我们可以通过微服务名称调用,不推荐
      enabled: true #是否开启网关
      routes:
      - id: order_route #路由ID,全局唯一
        #uri: http://localhost:8020 #目标微服务的请求地址和端口  我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
        uri: lb://mall-order
        predicates:
        - Path=/order/**
        filters:
        - AddRequestHeader=X-Request-color, red  #添加请求头
        - AddRequestParameter=color, blue   # 添加请求参数
  

(3)测试效果 分别访问 http://localhost:8888/order/testgateway、http://localhost:8888/order/testgateway2、http://localhost:8888/order/testgateway3

查看order服务控制台 请求头和请求参数都已拿到

image-20220522173721291

2 添加微服务上下文前缀(经常使用)

我们知道我们的微服务一般都会添加一个上下文路径,此时我们可以在网关层的过滤配置直接拼接这个url,比如

(1)我们的order服务添加一个上下文路径

server:
  port: 8020
  servlet:
    context-path: test

(2)在yaml配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true  #为true代表 我们可以通过微服务名称调用,不推荐
      enabled: true #是否开启网关
      routes:
      - id: order_route #路由ID,全局唯一
        #uri: http://localhost:8020 #目标微服务的请求地址和端口  我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
        uri: lb://mall-order
        predicates:
        - Path=/order/**
        #- CheckAuth=auth
        filters:
        - PrefixPath=/test  # 添加前缀 对应微服务需要配置context-path

(3)测试效果,我们访问路径不需要添加test,此时gateway会为我们自动拼接,访问http://localhost:8888/order/findOrderByUserId/1

SpringCloud-Gateway网关学习和实战_第12张图片

3 重定向

(1)配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true  #为true代表 我们可以通过微服务名称调用,不推荐
      enabled: true #是否开启网关
      routes:
      - id: order_route #路由ID,全局唯一
        #uri: http://localhost:8020 #目标微服务的请求地址和端口  我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
        uri: lb://mall-order
        predicates:
        - Path=/order/**
        #- CheckAuth=auth
        filters:
        - PrefixPath=/test  # 添加前缀 对应微服务需要配置context-path
        - RedirectTo=302, http://baidu.com

(2)访问http://localhost:8888/order/findOrderByUserId/1 出现百度的页面

SpringCloud-Gateway网关学习和实战_第13张图片

4 自定义过滤器工厂

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

/**
 * @author wcy
 */
@Component
@Slf4j
public class CheckAuthGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {

    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return (exchange, chain) -> {
            log.info("调用CheckAuthGatewayFilterFactory==="
                    + config.getName() + ":" + config.getValue());
            // TODO
            return chain.filter(exchange);
        };
    }
}

(2)yaml配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true  #为true代表 我们可以通过微服务名称调用,不推荐
      enabled: true #是否开启网关
      routes:
      - id: order_route #路由ID,全局唯一
        #uri: http://localhost:8020 #目标微服务的请求地址和端口  我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
        uri: lb://mall-order
        predicates:
        - Path=/order/**
        filters:
        - PrefixPath=/test  # 添加前缀 对应微服务需要配置context-path
        - CheckAuth=username,qianyue #配置自定义的过滤器工厂

(3)访问 http://localhost:8888/order/findOrderByUserId/1 查看控制台 可以拿到我们配置的参数,这样我们可以做一个校验过滤的配置

image-20220522180404872

GlobalFilter

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

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

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 的内容。

      routes:
      - id: order_route  #路由ID,全局唯一,建议配合服务名
        #uri: http://localhost:8020  #目标微服务的请求地址和端口
        uri: lb://mall-order  #lb 整合负载均衡器ribbon,loadbalancer
2 自定义全局过滤器

(1)编写过滤器CheckIpFilter实现GlobalFilter, Ordered接口

@Component
@Slf4j
public class CheckIpFilter implements GlobalFilter, Ordered {

    @Override
    public int getOrder() {
        return 0;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        HttpHeaders headers = exchange.getRequest().getHeaders();
        //模拟对 IP 的访问限制,即不在 IP 白名单中就不能调用的需求
        if (getIp(headers).equals("127.0.0.1")) {
            log.info("======非法访问======");
            ServerHttpResponse response = exchange.getResponse();
            byte[] bytes = new String("======非法访问======").getBytes();
            response.setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            DataBuffer buffer = response.bufferFactory().wrap(bytes);
            response.getHeaders().add("Content-Type",
                    "application/json;charset=UTF-8");
            return exchange.getResponse().writeWith(Mono.just(buffer));
        }
        return chain.filter(exchange);
    }

    private String getIp(HttpHeaders headers) {
        return headers.getHost().getHostName();
    }
}

(2)访问http://127.0.0.1:8888/order/findOrderByUserId/1 出现非法访问,测试成功

SpringCloud-Gateway网关学习和实战_第14张图片

2.3.4 Gateway解决跨域问题

yaml配置

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      globalcors:
        cors-configurations:   #解决跨域问题
          - Get
          - POST
          - DELETE
          - PUT
          - OPTION
      discovery:
        locator:
          enabled: true  #为true代表 我们可以通过微服务名称调用,不推荐
      enabled: true #是否开启网关
      routes:
      - id: order_route #路由ID,全局唯一
        #uri: http://localhost:8020 #目标微服务的请求地址和端口  我们服务交给了nacos 如果有集群,直接指定IP加端口是不可取的
        uri: lb://mall-order
        predicates:
        - Path=/order/**
        #- After=2022-05-22T16:35:05.794+08:00[Asia/Shanghai] #指定时间后才可以访问
        #- Cookie=username,qianyue  #key=username value=qianyue
        #- Header=X-Request-Id,\d+  #表示key为X-Request-Id, value必须为整数
        #- CheckAuth=auth
        filters:
        #- AddRequestHeader=X-Request-color, red  #添加请求头
        #- AddRequestParameter=color, blue   # 添加请求参数
        - PrefixPath=/test  # 添加前缀 对应微服务需要配置context-path
        #- RedirectTo=302, http://baidu.com
        #- CheckAuth=username,qianyue #配置自定义的过滤器工厂

2.3.5 整合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.3.5.1 环境搭建

1.新建Module,引入依赖

    <dependencies>

        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-gatewayartifactId>
        dependency>

        
        <dependency>
        <groupId>com.alibaba.cspgroupId>
        <artifactId>sentinel-spring-cloud-gateway-adapterartifactId>
        dependency>



        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
        dependency>

        
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
        dependency>

    dependencies>

2.yaml配置

server:
  port: 8888
spring:
  application:
    name: mall-gateway-sentinel
  main:
    allow-bean-definition-overriding: true
  #配置nacos注册中心地址
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

    sentinel:
      transport:
        # 添加sentinel的控制台地址
        dashboard: 127.0.0.1:8080
        # 指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
        #port: 8719

    gateway:
      discovery:
        locator:
          # 默认为false,设为true开启通过微服务创建路由的功能,即可以通过微服务名访问服务
          # http://localhost:8888/mall-order/order/findOrderByUserId/1
          enabled: false
      # 是否开启网关
      enabled: true

      #设置路由:路由id、路由到微服务的uri、断言
      routes:
        - id: order_route  #路由ID,全局唯一,建议配合服务名
          uri: lb://mall-order  #lb 整合负载均衡器ribbon,loadbalancer
          predicates:
            - Path=/order/**

        - id: user_route
          uri: lb://mall-user  #lb 整合负载均衡器ribbon,loadbalancer
          predicates:
            - Path=/user/**

3.编写配置类

/**
 * @author wcy
 */
@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();
    }
}

4.配置流控规则 访问http://127.0.0.1:8888/order/findOrderByUserId/1 在sentinel控制台配置流控规则 可以看出此时的资源名称就是我们的route-id

SpringCloud-Gateway网关学习和实战_第15张图片

5.测试 快速访问访问http://127.0.0.1:8888/order/findOrderByUserId/1 说明我们流控成功。

SpringCloud-Gateway网关学习和实战_第16张图片

2.3.5.2 手动配置流控规则

(1)编写配置类

/**
 * @author wcy
 */
@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();
    }


    @PostConstruct
    public void doInit() {
//        //初始化自定义的API
        initCustomizedApis();
//        //初始化网关限流规则
        initGatewayRules();
//        //自定义限流异常处理器
        initBlockRequestHandler();
    }



    private void initCustomizedApis() {
        Set<ApiDefinition> definitions = new HashSet<>();
        // 资源保护名user_service_api    Path:/user/**
        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("user_service_api")
                .setCount(2)
                .setIntervalSec(1)
        );

        // 加载网关规则
        GatewayRuleManager.loadRules(rules);
    }

    private void initBlockRequestHandler() {
        BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
            @Override
            public 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)访问127.0.0.1:8888/user/findOrderByUserId/1 查看控制台

SpringCloud-Gateway网关学习和实战_第17张图片

3.测试 快速点击127.0.0.1:8888/user/findOrderByUserId/1 出现降级

SpringCloud-Gateway网关学习和实战_第18张图片

其实我们在流控规则控制台查看并没有我们手动设置的流控规则,这是一个坑,是因为我们应该导入另外一个包就可以配置

SpringCloud-Gateway网关学习和实战_第19张图片

2.3.5.3 Gateway整合Sentinel

1.pom 把上边的适配包去掉 更换为整合包

        
		<dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-alibaba-sentinel-gatewayartifactId>
        dependency>

2.重新启动Sentinel控制台,发现我们的菜单发生改变

SpringCloud-Gateway网关学习和实战_第20张图片

3.配置流控规则,界面也和我们之前的界面不一样

SpringCloud-Gateway网关学习和实战_第21张图片

4.新增一个API流控规则

添加API分组

SpringCloud-Gateway网关学习和实战_第22张图片

添加流控规则

SpringCloud-Gateway网关学习和实战_第23张图片

5.测试 访问127.0.0.1:8888/user/findOrderByUserId/1 流控成功

SpringCloud-Gateway网关学习和实战_第24张图片

你可能感兴趣的:(微服务,spring,cloud,gateway,学习)