一、Spring Cloud Gateway内部流程源码分析

(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值等于指定的值,才能访问;
2、要求某个服务的用户只允许在23:00 - 6:00这个时间段内才可以访问;

1、自定义谓词具体步骤:

  • (1)首先定义一个配置类,用于承载配置参数;
  • (2)定义一个路由谓词工厂;
  • 注:TokenRoutePredicateFactory类,前面的Token与.yml配置文件里面配置的名字对应,后面的RoutePredicateFactory名字是固定的,不能随便写,这是Spring Cloud Gateway的约定,类名须为“谓词工厂名(比如:Token)” + RoutePredicateFactory
  • (3)在配置文件中启用该路由谓词工厂,即配置一个Token=123456;

时间格式不是随便配置,而是Spring Cloud Gateway的默认时间格式,采用JDK8里面的格式化:

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT);
String nowTime = dateTimeFormatter.format(ZonedDateTime.now());
System.out.println(nowTime);

到此为止就实现了一个自定义路由谓词工厂,若此时token值不相等,不在允许的访问时间段内,访问就会报404;

2、Spring Cloud Gateway谓词不匹配404处理

处理的顶层接口是WebExceptionHandler

默认实现是DefaultErrorWebExceptionHandler

springcloud gateway自定义协议转化实现 spring gateway 自定义路由_java


我们需要覆盖它的默认实现DefaultErrorWebExceptionHandler,覆盖里面的方法,在方法里面编写我们想要返回的结果,参看我们git代码;

三 、Spring Cloud Gateway自定义路由过滤器

网关过滤器的顶层接口是GatewayFilterFactory
通常情况下可以继承AbstractGatewayFilterFactory实现自定义网关过滤器;
或者继承AbstractNameValueGatewayFilterFactory,该方式配置方式更简单,然后覆盖里面的一个方法,具体参考一下我们的样例代码,实际上理解流程思路即可,真正需要做的时候,查一下就可以;

1、Spring Cloud Gateway全局过滤器

springcloud gateway自定义协议转化实现 spring gateway 自定义路由_Cloud_02


上面的过滤器工厂是执行在指定路由之上,可以称为路由过滤器(或者局部过滤器),而全局过滤器是作用于所有的路由上,对所有的路由进行过滤;

全局过滤器的顶层接口是GlobalFilter ,和GatewayFilter 有一样的接口定义,只不过GlobalFilter 会作用于所有路由;

全局过滤器有执行顺序问题,通过getOrder()方法的返回值决定执行顺序,数值越小越靠前执行;
Spring cloud gateway默认内置了很多全局过滤器,比如:

  1. Combined Global Filter and GatewayFilter Ordering
  2. Forward Routing Filter
  3. The LoadBalancerClient Filter
  4. The ReactiveLoadBalancerClientFilter
  5. The Netty Routing Filter
  6. The Netty Write Response Filter
  7. The RouteToRequestUrl Filter
  8. The Websocket Routing Filter
  9. The Gateway Metrics Filter
  10. Marking An Exchange As Routed

2、自定义全局过滤器示例

import lombok.extern.slf4j.Slf4j;
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.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 自定义全局Filter
 *
 */
@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集成ribbon负载均衡

实现原理是在全局LoadBalancerClientFilter中进行拦截,然后再该过滤器中依赖LoadBalancerClient loadBalancer,而此负载均衡接口的具体实现是RibbonLoadBalancerClient,即spring cloud gateway已经整合好了ribbon,已经可以实现负载均衡,我们不需要做任何工作,网关对后端微服务的转发就已经具有负载均衡功能;

五 、Spring cloud gateway跨域CORS

我们知道,传统的Ajax请求只能获取在同一个域名下的资源,但是HTML5规范中打破了这种限制,允许Ajax发起跨域的请求;(只是需要设置一下)

其实浏览器本身是可以发起跨域请求的,比如你可以链接一个另一个域名下的图片或者js,比如

,但是javascript脚本是不能获取这些另一个域名下的资源内容的;

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

这种CORS使用了一个额外的HTTP响应头来赋予当前user-agent(浏览器)获得跨域资源的权限,这里的跨域也就是Cross-Origin的概念,这里的权限就是访问另一个域名下的资源权限;

CORS是现在HTML5标准中的一部分,在大部分现代浏览器中都有所支持,可能在某些老版本的浏览器不支持CORS,如果要兼容一些老的浏览器版本,则需要采用JSONP进行跨域请求;

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

如果 访问协议、端口(如果指定了端口的话)、host都相同,则称之为同源(不跨域),否则为非同源(跨域);
比如源链接: http:///dir/page.html

springcloud gateway自定义协议转化实现 spring gateway 自定义路由_java_03

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

/**
 * 配置网关跨域cors请求支持
 */
@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource source = new 
UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);
        return new CorsWebFilter(source);
    }
}