gateway网关

1.概念

Gateway网关是我们服务的守门神,所有微服务的统一入口。

网关的核心功能特性:路由转发,负载均衡,限流,权限控制

2.使用

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>

2.application.yml文件

server:
  port: 9000


spring:
  application:
    name: service-gateway

  ###nacos注册中心
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
#    gateway:
#  #      #路由规则
#        routes:
#          - id: gateway-product           #路由id,唯一
#  #          uri: http://localhost:8081/  #目标uri,路由到微服务的地址
#            uri: lb://service-product     # 根据服务名称进行路由    lb:loadbalance  负载均衡
#            predicates:                   # 采用断言的判断条件
#              - Path=/product/**          # 匹配对应的url请求,将匹配到的请求追加到目标uri的后面   访问/product/**   实际上访问的是 service-product/product/**
#            filters:                      # 网关过滤器
#              - name: RequestRateLimiter   ##内置过滤器,还可以自定义过滤器和全局过滤器
#                args:
##                  URI限流        超过这个速率会报429错误
#                  redis-rate-limiter.replenishRate: 1  # 令牌桶每秒填充平均速率
#                  redis-rate-limiter.burstCapacity: 2  # 令牌桶的上限
#                  key-resolver: "#{@pathKeyResolver}"  # 使用SpEL表达式从Spring容器中获取Bean对象


######第一种方式   gateway 动态路由转发(推荐使用,不用一个服务一个服务地配)
    ######   访问的时候加上service名称   eg:localhost:9000/product/save ->
    #                                    localhost:9000/service-product/product/save
    gateway:
      discovery:
        locator:
          ####开启与服务注册中心进行结合,通过serviceid 转发到具体的服务实例
          enabled: true                 #开启基于服务发现的路由规则
          lower-case-service-id: true   #是否将服务名称转小写


    ############################################################################
    #### 第二种方式   gateway网关     需要一个服务一个服务地配置
#    gateway:
#      #路由规则
#      routes:
#        - id: gateway-product   #路由id,唯一
##          uri: http://localhost:8081/  #目标uri,路由到微服务的地址
#          uri: lb://service-product  ###根据服务名称进行路由    lb:loadbalance  负载均衡
#
#          predicates:          # 采用断言的判断条件
#            - Path=/product/**  #  匹配对应的url请求,将匹配到的请求追加到目标uri之后
#            - Query=token      #匹配请求参数,请求的参数中带token的就给你路由
#            - Method=GET       #匹配任意get请求
#            - After= 具体时间   #在这个时间之后的请求可以路由 同理还有Before
#            - RemoteAddr=127.0.0.1/0  #匹配远程地址请求是RemoteAddr的请求
#            - Header=Request-Id    # 匹配请求头包含Request-Id 的请求
#  gateway  工作原理
#  用户访问带url里面带有  /product/  就把请求路由到http://localhost:8081/
#  再把后面的path添加上拼接成最终的url访问路径进行访问
#  最终访问路径是  http://localhost:8081/product/**

3.配置过滤器
gateway内置过滤器有31个,常用的有
AddRequestHeader 给当前请求添加一个请求头
RemoveRequestHeader 移除请求中的一个请求头
AddResponseHeader 给响应结果中添加一个响应头
RemoveResponseHeader 从响应结果中移除有一个响应头
RequestRateLimiter 限制请求的流量
也可以自己实现GatewayFilter接口自定义过滤器(用的不多),然后把该过滤器添加到配置类里边,例如:

public class CustomGatewayFilter implements GatewayFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //TODO 这里面写业务逻辑
        System.out.println("自定义网关过滤器被执行");
        return chain.filter(exchange);   //继续往下执行
    }

    /**
     * 如果有多个过滤器  ,此方法返回的数值越小,执行优先级越高
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}
@Configuration
public class GatewayRoutesConfiguration {

    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder builder) {
        return builder.routes().route(r -> r.
                //断言,判断条件
                path("/product/**")
                //目标uri,路由到微服务的地址
                .uri("lb://service-product")
                //注册自定义网关过滤器
                .filters(new CustomGatewayFilter())
                //路由id,唯一
                .id("product-service"))
                .build();



    }
}

使用全局过滤器,实现GlobalFilter接口,可以拿到request里面的参数用于权限判断

@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("执行全局过滤器");
        ServerHttpRequest request = exchange.getRequest();

        //TODO  业务逻辑
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

3.gateway结合sentinel限流

1.增加依赖

<!--        sentinel-gateway 依赖-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
        </dependency>

2.application.yml文件

server:
  port: 9001

spring:
  application:
    name: gateway-sentinel
  cloud:
    sentinel:
      filter:
        enabled: false  #不对网关进行限流
    gateway:
      #与服务注册中心配合使用,通过service  id进行路由转发
      discovery:
        locator:
          lower-case-service-id: true    #将服务名称转小写
          enabled: true
      #路由规则
      routes:
        - id: service-product
          uri: lb://service-product
          predicates:
            - Path=/product/**
        - id: service-order
          uri: lb://service-order
          predicates:
            - Path=/order/**
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

添加配置类 (分组限流)并自定义限流异常处理器

@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() {
        // By default the order is HIGHEST_PRECEDENCE
        return new SentinelGatewayFilter();
    }

    /**
     * 容器初始化时候执行该方法
     */
    @PostConstruct
    public void doInit() {
        //加载网关限流规则
        initGatewayRules();
        //加载自定义限流异常处理器
        initBlockHandler();
    }


    /**
     * 网关限流规则
     */
    private void initGatewayRules() {
        HashSet<GatewayFlowRule> rules = new HashSet<GatewayFlowRule>();

        /**
         * resource :资源名称 ,可以是网关中的routes名称/id,也可以时自定义API分组名称
         * count  :限流阈值
         * setIntervalSec:统计时间窗口,单位是秒
         *
         * 60秒内只能访问3次   超过3次就会报 Blocked by Sentinel: ParamFlowException异常
         */

//        rules.add(new GatewayFlowRule("service-product")
//                .setCount(3)
//                .setIntervalSec(60));

        //添加分组限流规则,和 initCustomizedApis()方法一起使用, 不同api限流规则不同。
        rules.add(new GatewayFlowRule("product-api")
                .setCount(3)
                .setIntervalSec(60));
        rules.add(new GatewayFlowRule("order-api")
                .setCount(5)
                .setIntervalSec(60));
        GatewayRuleManager.loadRules(rules);
        initCustomizedApis();
    }

    /**
     * 自定义限流异常处理器    替代 Blocked by Sentinel: ParamFlowException异常
     */
    private void initBlockHandler() {
        BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                Map<String, String> map = new HashMap<>();

                map.put("code", String.valueOf(HttpStatus.TOO_MANY_REQUESTS.value()));
                map.put("message", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());
                return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(BodyInserters.fromValue(map));
            }
        };
        //加载自定义限流异常处理器
        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }

    /**
     * 自定义API分组限流  不同的组限流规则不同
     */
    private void initCustomizedApis(){
        Set<ApiDefinition> definitions = new HashSet<>();
        //product-api组
        ApiDefinition api1 = new ApiDefinition("product-api")
                .setPredicateItems(new HashSet<ApiPredicateItem>(){{
                    add(new ApiPathPredicateItem().setPattern("/service-product/product/**")   //对product下所有路径进行限流
                            .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
                }});
        //order-api组
        ApiDefinition api2 = new ApiDefinition("order-api")
                .setPredicateItems(new HashSet<ApiPredicateItem>(){{
                    add(new ApiPathPredicateItem().setPattern("/service-order/order/index"));  // 对/order/index/进行限流
                }});
        definitions.add(api1);
        definitions.add(api2);
        //加载限流分组
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值