Spring Cloud Gateway集成Sentinel规则持久化以及自定义谓词和filter(过滤器)

Spring Cloud Gateway集成ribbon负载均衡:

  gateway集成ribbon的原理是在全局LoadBalancerClientFilter中进行拦截,然后该过滤器当中依赖LoadBalancerClient loadBalancer,然而负载均衡接口的具体实现是RibbonLoadBalancerClient implements LoadBalancerClient,所以gateway已经整合了ribbon,实现了负载均衡,不需要任何处理网关对微服务的请求转发已经具有负载均衡。
Spring Cloud Gateway集成Sentinel规则持久化以及自定义谓词和filter(过滤器)_第1张图片
Spring Cloud Gateway集成Sentinel规则持久化以及自定义谓词和filter(过滤器)_第2张图片

Spring Cloud Gateway集成Sentinel:

  网关集成Sentinel是为了流控熔断降级
1、添加依赖

		<!-- sentinel-spring-cloud-gateway-adapter -->
        
            com.alibaba.csp</groupId>
            sentinel-spring-cloud-gateway-adapter</artifactId>
            1.7.2</version>
        </dependency>
        <!--sentinel-datasource-extension数据源扩展-->
		
		    com.alibaba.csp</groupId>
		    sentinel-datasource-extension</artifactId>
		</dependency>
		<!--sentinel数据持久化-->
		
		    com.alibaba.csp</groupId>
		    sentinel-datasource-nacos</artifactId>
		</dependency>

2、添加Sentinel控制台配置

#sentinel dashboard管理后台
    sentinel:
      eager: true
      transport:
        dashboard: 192.168.25.1:8080

      #配置sentinel规则持久化到nacos
      datasource:
        flow:     #流控
          nacos:
            server-addr: 47.110.237.194:80
            data-id: ${spring.application.name}-flow.json
            group-id: DEFAULT_GROUP
            rule-type: flow
            data-type: json

        degrade:
          nacos:    #降级
            server-addr: 47.110.237.194:80
            data-id: ${spring.application.name}-degrade.json
            group-id: DEFAULT_GROUP
            rule-type: degrade
            data-type: json

3、在Spring容器当中配置一个Sentinel的全局过滤器

    /**
     * 配置一个Sentinel的全局过滤器;
     * @return
     */
    @Bean
    @Order(-1)
    public GlobalFilter sentinelGatewayFilter(){
        return new SentinelGatewayFilter();
    }

两种持久化规则:

  第一种:持久化到本地文件
  第二种:在application.yaml配置持久化规则

      #配置sentinel规则持久化到nacos
      datasource:
        flow:     #流控
          nacos:
            server-addr: 47.110.237.194:80
            data-id: ${spring.application.name}-flow.json
            group-id: DEFAULT_GROUP
            rule-type: flow
            data-type: json

        degrade:
          nacos:    #降级
            server-addr: 47.110.237.194:80
            data-id: ${spring.application.name}-degrade.json
            group-id: DEFAULT_GROUP
            rule-type: degrade
            data-type: json

在nacos配置中心配置流控规则:

[
	{
		"resource": "route1",
		"controlBehavior": 0,
		"count": 1.0,
		"grade": 1,
		"limitApp": "default",
		"strategy": 0
	}
,
	{
		"resource": "route2",
		"controlBehavior": 0,
		"count": 2.0,
		"grade": 1,
		"limitApp": "default",
		"strategy": 0
	}
,
	{
		"resource": "route3",
		"controlBehavior": 0,
		"count": 3.0,
		"grade": 1,
		"limitApp": "default",
		"strategy": 0
	}
]

Spring Cloud Gateway内部流程源码分析:

Spring Cloud Gateway集成Sentinel规则持久化以及自定义谓词和filter(过滤器)_第3张图片
(1)根据自动装配spring-cloud-gateway-core.jar的spring.factories;
(2)GatewayClassPathWarningAutoConfiguration检查前端控制器;
(3)网关自动配置GatewayAutoConfiguration;
(4)RoutePredicateHandlerMapping.getHandlerInternal(…)获取Route;
(5)执行FilteringWebHandler

Spring Cloud Gateway自定义谓词:

  Spring Cloud Gateway内置了一系列的路由谓词工厂,但是如果这些内置的路由谓词工厂不能满足业务需求的话,可以自定义路由谓词工厂来实现特定的需求;
举例如下:
1、要求请求必须携带一个token,并且token值等于指定的值,才能访问;

自定义谓词具体步骤:

(1)首先定义一个配置类,用于承载配置参数;

cloud:
    #配置网关
    gateway:
      discovery:
        locator:
          enabled: true #启用DiscoveryClient网关集成,可以实现服务的发现

      #配置网关路由转发规则
      routes:
        - id: route1
          uri: lb://29-nacos-discovery-customer
          predicates: #谓词:判断,是不是?对不对?是否匹配?
            - Path=/test2, /notFound-feign, /index, /echo
            - Token=123456

(2)定义一个路由谓词工厂;
注:TokenRoutePredicateFactory类,前面的Token与.yml配置文件里面配置的名字对应,后面的RoutePredicateFactory名字是固定的,不能随便写,这是Spring Cloud Gateway的约定,类名须为“谓词工厂名(比如:Token)” + RoutePredicateFactory

@Slf4j
@Component
public class TokenRoutePredicateFactory extends AbstractRoutePredicateFactory<TokenConfig> {

    public TokenRoutePredicateFactory() {
        super(TokenConfig.class);
    }


    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("token");
    }

    @Override
    public Predicate<ServerWebExchange> apply(TokenConfig tokenConfig) {
        // (T t) -> true
        return exchange -> {
            MultiValueMap<String, String> valueMap = exchange.getRequest().getQueryParams();

            boolean flag = false;

            List<String> list = new ArrayList<>();

            valueMap.forEach((k, v) -> {
                list.addAll(v);
            });

            for (String s : list) {
                log.info("Token -> {} ", s);
                if (StringUtils.equalsIgnoreCase(s, tokenConfig.getToken())) {
                    flag = true;
                    break;
                }
            }
            return flag;
        };
    }
}

结果如下所示

Spring Cloud Gateway谓词不匹配404处理:

处理的顶层接口是WebExceptionHandler
默认实现是DefaultErrorWebExceptionHandler
Spring Cloud Gateway集成Sentinel规则持久化以及自定义谓词和filter(过滤器)_第4张图片

/**
 * @author 
 * @Description: 自定义错误页面
 * @date 2021/1/12 23:44
 */
public class MyErrorWebExceptionHandler extends DefaultErrorWebExceptionHandler {
    /**
     * Create a new {@code DefaultErrorWebExceptionHandler} instance.
     *
     * @param errorAttributes    the error attributes
     * @param resourceProperties the resources configuration properties
     * @param errorProperties    the error configuration properties
     * @param applicationContext the current application context
     */
    public MyErrorWebExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties, ErrorProperties errorProperties, ApplicationContext applicationContext) {
        super(errorAttributes, resourceProperties, errorProperties, applicationContext);
    }

    /**
     * 指定响应处理方法为JSON处理的方法
     *
     * @param errorAttributes
     */
    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
    }

    /**
     * 根据code获取对应的HttpStatus
     * @param errorAttributes
     * @return
     */
    @Override
    protected int getHttpStatus(Map<String, Object> errorAttributes){
        int status = (int)errorAttributes.get("status");
        return status;
    }

    /**
     * 构建异常信息
     * @param request
     * @param ex
     * @return
     */
    private String buildMessage(ServerRequest request, Throwable ex) {
        StringBuilder message = new StringBuilder("Failed to handle request [");
        message.append(request.methodName());
        message.append(" ");
        message.append(request.uri());
        message.append("]");
        if (ex != null) {
            message.append(": ");
            message.append(ex.getMessage());
        }
        return message.toString();
    }

    /**
     * 构建返回的JSON数据格式
     *
     * @param status		状态码
     * @param errorMessage  异常信息
     * @return
     */
    public static Map<String, Object> response(int status, String errorMessage) {
        Map<String, Object> map = new HashMap<>();
        map.put("status",status);
        map.put("errorMessage",errorMessage);
        map.put("data",null);
        return map;
    }
}

Spring Cloud Gateway全局过滤器:

Spring Cloud Gateway集成Sentinel规则持久化以及自定义谓词和filter(过滤器)_第5张图片
  过滤器工厂是执行在指定路由之上,可以称为路由过滤器(或者局部过滤器),而全局过滤器是作用于所有的路由上,对所有的路由进行过滤;
  全局过滤器的顶层接口是GlobalFilter ,和GatewayFilter 有一样的接口定义,只不过GlobalFilter 会作用于所有路由;
  全局过滤器有执行顺序问题,通过getOrder()方法的返回值决定执行顺序,数值越小越靠前执行;

/**
 * @author 
 * @Description: 自定义全局Filter
 * @date 2021/1/13 0:16
 */
@Slf4j
@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("自定义全局Filter......");

        MultiValueMap<String, String> valueMap = exchange.getRequest().getQueryParams();

        valueMap.forEach((k,v) -> {
            log.info("全局filter参数: ,{}",k);
            v.forEach( s -> {
                log.info("全局filter参数值:,{}",s);
            });
        });
        return chain.filter(exchange);
    }

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

Spring Cloud Gateway自定义网关路由过滤器:

  网关过滤器的顶层接口GatewayFilterFactory,通常继承AbstractGatewayFilterFactory实现自定义网关过滤器;或者继承AbstractNameValueGatewayFilterFactory,该方式配置方式更简单,然后覆盖里面的一个方法

/**
 * @author 
 * @Description: 自定义过滤器
 * @date 2021/1/12 23:56
 */
@Slf4j
@Component
public class RequestLogGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return (ServerWebExchange exchange, GatewayFilterChain chain) -> {
          log.info("请求网关:,{},{}",config.getName(),config.getValue());
            MultiValueMap<String, String> valueMap = exchange.getRequest().getQueryParams();
            valueMap.forEach((k,v) -> {
                log.info("自定义过滤器请求参数:{}",k);
                v.forEach(s -> {
                    log.info("自定义过滤器请求参数值 {}",s);
                });
            });
            return chain.filter(exchange);
        };
    }
}
cloud:
    #配置网关
    gateway:
      discovery:
        locator:
          enabled: true #启用DiscoveryClient网关集成,可以实现服务的发现

      #配置网关路由转发规则
      routes:
        - id: route1
          uri: lb://29-nacos-discovery-customer
          predicates: #谓词:判断,是不是?对不对?是否匹配?
            - Path=/test2, /notFound-feign, /index
            - Token=123456

          filters:
            - AddRequestParameter=color, black
            - RequestLog=prefix, gatewaytest #自定义的filter

Spring Cloud Gateway集成Sentinel规则持久化以及自定义谓词和filter(过滤器)_第6张图片

Spring cloud gateway跨域CORS:

  CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing),它允许浏览器向跨域的另一台服务器发出XMLHttpRequest请求,从而克服了AJAX只能访问同域名下的资源的限制。

同源与非同源的定义(跨域和不跨域):

  如果 访问协议、端口(如果指定了端口的话)、host都相同,则称之为同源(不跨域),否则为非同源(跨域);
源链接:http://www.mydown.com/soft/453/473302453.shtml

URL 是否同源 原因
http://www.mydown.com/soft/227/1506342727.shtml
https://www.mydown.com/soft/453/473302453.shtml 协议不同
http://www.mydown.com:81/soft/227/1506342727.shtml 端口不同
http://www.bear20.com/window/4531/473302453.html host不同

Spring Cloud Gateway解决跨域问题,只需要配置如下代码即可:

/**
 * @author 
 * @Description: 解决跨域问题
 * @date 2021/1/13 23:46
 */
@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsWebFilter(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedMethod("*");    //是什么请求方法,比如 GET POST PUT DELETE .....
        corsConfiguration.addAllowedOrigin("*");    //来自哪个域名的请求,*号表示所有
        corsConfiguration.addAllowedHeader("*");    //是什么请求头

        org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", corsConfiguration);

        return new CorsWebFilter(source);

    }
}

你可能感兴趣的:(Spring,cloud,Alibaba,spring,cloud,alibaba,gateway,filter,网关,java)