微服务网关GateWay

image

基本功能:
安全,监控/埋点,限流等

image
image

2.1路由配置

2.1.1搭建环境
1. 创建工程导入坐标

 <!--
         springcloudgateway的内部是通过netty+webflux实现
         webflux实现和springmvc存在冲突
         -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
2.  配置启动类
@SpringBootApplication
public class ApiGateWayServerApplication {

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

3.  配置yml文件
server:
  port: 8080
spring:
  application:
    name: api_gateway_server
  cloud:
    gateway:
      routes:
        #配置路由 路由id,路由到微服务的uri,断言(判断条件)
        - id: product-service
          uri: http://127.0.0.1:9001
          predicates:
            - Path=/product/**

2.1.2路由规则

image
image
image
image
image

2.1.3动态路由(面向服务的路由)

server:
  port: 8080
spring:
  application:
    name: api_gateway_server
  cloud:
    gateway:
      routes:
        #配置路由 路由id,路由到微服务的uri,断言(判断条件)
        - id: product-service
#          uri: http://127.0.0.1:9001
          uri: lb://service-product # lb://根据微服务名称从注册中心拉取服务请求路径
          predicates:
            - Path=/product/** #路由条件 path:路由匹配条件

#配置Eureka
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9000/eureka/
  instance:
    prefer-ip-address: true #使用IP地址注册

2.1.4路径重写

cloud:
    gateway:
      routes:
        #配置路由 路由id,路由到微服务的uri,断言(判断条件)
        - id: product-service
#          uri: http://127.0.0.1:9001
          uri: lb://service-product # lb://根据微服务名称从注册中心拉取服务请求路径
          predicates:
           # - Path=/product/** #路由条件 path:路由匹配条件
          - Path=/product-service/** #讲当前请求转发到 http://127.0.0.1:9001/product/1
          filters:  #配置路由过滤器
          - RewritePath=/product-service/(?<segment>.*),/$\{segment} #RewritePath路径重写的过滤器,在yml中$写为$\
          #配置自动的根据微服务名称进行路由转发  #http://localhost:8080/service-product/product/1

2.1.5开启微服务名称转发

    #配置自动的根据微服务名称进行路由转发  #http://localhost:8080/service-product/product/1
      discovery:
        locator:
          enabled: true  #开启根据服务名称自动转发
          lower-case-service-id: true #微服务名称以小写形式呈现

2.2过滤器

server:
  port: 8080
spring:
  application:
    name: api_gateway_server
  cloud:
    gateway:
      routes:
        #配置路由 路由id,路由到微服务的uri,断言(判断条件)
        - id: product-service
#          uri: http://127.0.0.1:9001
          uri: lb://service-product # lb://根据微服务名称从注册中心拉取服务请求路径
          predicates:
           # - Path=/product/** #路由条件 path:路由匹配条件
          - Path=/product-service/** #讲当前请求转发到 http://127.0.0.1:9001/product/1
          filters:  #配置路由过滤器
          - RewritePath=/product-service/(?<segment>.*),/$\{segment} #RewritePath路径重写的过滤器,在yml中$写为$\

#配置Eureka
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9000/eureka/
  instance:
    prefer-ip-address: true #使用IP地址注册

image
image
image
image
image
image
image
image

全局过滤器代码:
package com.yxkj.filter;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @USER: 
 * @DATE: 2021-07-12
 * @description:功能描述  自定义全局过滤器
 *   实现 globalfilter,ordered接口
 */
@Component
public class LoginUserFilter implements GlobalFilter, Ordered {
    /**
     * 执行过滤器的业务逻辑
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("执行了自定义的全局过滤器");
        return chain.filter(exchange); //继续向下执行
    }

    /**
     * 指定过滤器的执行顺序,返回值越小,执行优先级越高
     * @return
     */
    @Override
    public int getOrder() {
        return 1;
    }
}

2.3统一鉴权

image
image

2.4网关限流

2.4.1基于filter限流

image
image
(1)准备工作
redis
在工程中引入redis相应的依赖

 <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-actuator</artifactId>
       </dependency>

(2)修改网关中的application.yml配置

server:
 port: 8080
spring:
 application:
   name: api_gateway_server
 redis:
   host: localhost
   pool: 6379
   database: 0

 cloud:
   gateway:
     routes:
       - id: service-product
         uri: lb://service-product
         predicates:
           - Path=/product-service/**
         filters:
           - name: RequestRateLimiter #使用限流过滤器,是springcloud getway提供的
             args:
               #使用SpEl从容器中获取对象
               key-resolver: '#{@pathKeyResolver}'
               #令牌桶每秒填充平均速率
               redis-rate-limiter.replenishRate: 1  #向令牌桶中填充的速率
               #令牌桶的上限
               redis-rate-limiter.burstCapacity: 3  #令牌桶的容量
           - RewritePath=/product-service/(?<segment>.*),/$\{segment} #RewritePath路径重写的过滤器,在yml中$写为$\

#配置Eureka
eureka:
 client:
   service-url:
     defaultZone: http://localhost:9000/eureka/
 instance:
   prefer-ip-address: true #使用IP地址注册

(3)配置redis中key的解析器KeySesover


import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @USER: 
 * @DATE: 2021-07-12
 * @description:功能描述
 */
@Configuration
public class KeyResolverConfiguration {
    /**
     * 编写基于请求路径的限流规则
     * //abc
     * //基于请求ip 127.0.0.1
     * //基于参数
     */
//    @Bean
//    public KeyResolver pathKeyResolver(){
//        //自定义的keyResolver
//        return new KeyResolver() {
//            /**
//             * ServerWebExchange 上下文参数
//             *
//             *
//             * @param exchange
//             * @return
//             */
//            @Override
//            public Mono<String> resolve(ServerWebExchange exchange) {
//                return   Mono.just( exchange.getRequest().getPath().toString());
//            }
//        };
//    }

    /**
     * 基于请求参数的限流
     * 请求 abc? userId=1
     * @return
     */
    @Bean
    public KeyResolver userKeyResolver(){
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
    }

}


2.4.2基于sentinel限流

Sentinel支持对Spring cloud Gateway、Zuul等主流的API Gateway进行限流

image
image
image

application.yml配置
server:
  port: 8080
spring:
  application:
    name: api_gateway_server
  redis:
    host: localhost
    pool: 6379
    database: 0

  cloud:
    gateway:
      routes:
        - id: service-product
          uri: lb://service-product
          predicates:
            - Path=/product-service/**
          filters:
#            - name: RequestRateLimiter #使用限流过滤器,是springcloud getway提供的
#              args:
#                #使用SpEl从容器中获取对象
#                key-resolver: '#{@userKeyResolver}'
#                #令牌桶每秒填充平均速率
#                redis-rate-limiter.replenishRate: 1  #向令牌桶中填充的速率
#                #令牌桶的上限
#                redis-rate-limiter.burstCapacity: 3  #令牌桶的容量
            - RewritePath=/product-service/(?<segment>.*),/$\{segment} #RewritePath路径重写的过滤器,在yml中$写为$\

#配置Eureka
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9000/eureka/
  instance:
    prefer-ip-address: true #使用IP地址注册
@Configuration
public class GatewayConfiguration {

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolvers.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    /**
     * 配置限流的异常处理器,SentinelGatewayBlockExceptionHandler
     * @return
     */
    @Bean
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler(){
        return new SentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer);

    }

    /**
     * 配置限流过滤器
     */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter(){
        return new SentinelGatewayFilter();

    }
    /**
     * 配置初始化的限流参数
     * 用于指定资源的限流规则
     * 1.资源名称(路由id)
     * 2.配置统计时间
     * 3.配置限流阈值
     */
    @PostConstruct
 public void initGatewayRules(){
        Set<GatewayFlowRule> rules = new HashSet<>();
      //  rules.add(new GatewayFlowRule("service-product").setCount(1).setIntervalSec(1));
//        rules.add(new GatewayFlowRule("order-api").setCount(1).setIntervalSec(1));
        rules.add(new GatewayFlowRule("product-api").setCount(1).setIntervalSec(1));
        GatewayRuleManager.loadRules(rules);
 }
    /**
     * 自定义限流处理器
     */
    @PostConstruct
    public void initBlockHandlers(){
        BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                Map<String,Object> map = new HashMap<>();
                map.put("code","101");
                map.put("message","限流啦!!!!稍等一会");
                return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON_UTF8)
                        .body(BodyInserters.fromObject(map));
            }
        };
        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }

    /**
     * 自定义API限流分组
     * 1.定义分组
     * 2.对小组配置限流规则
     */
    @PostConstruct
    private void initCustomizedApis(){
        Set<ApiDefinition> definitions = new HashSet<>();
        ApiDefinition api1 = new ApiDefinition("product-api")
                .setPredicateItems(new HashSet<ApiPredicateItem>(){{
                    add(new ApiPathPredicateItem().setPattern("/product-service/product/**").
                            setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));}});
       definitions.add(api1);
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }



}

2.5网关的高可用

image
image

posted @ 2021-07-11 16:45  风飘落叶  阅读(169)  评论(0编辑  收藏  举报