上一篇:【SpringCloud】九、Spring Cloud Gateway的基础介绍
(1)根据自动装配spring-cloud-gateway-core.jar的spring.factories;
(2)GatewayClassPathWarningAutoConfiguration检查前端控制器;
(3)网关自动配置GatewayAutoConfiguration;
(4)RoutePredicateHandlerMapping.getHandlerInternal(…)获取Route;
(5)执行FilteringWebHandler
Spring Cloud Gateway内置了一系列的路由谓词工厂,但是如果这些内置的路由谓词工厂不能满足业务需求的话,可以自定义路由谓词工厂来实现特定的需求;
下面列举两个例子:
1、要求请求必须携带一个token,并且token值等于指定的值,才能访问;
2、要求某个服务的用户只允许在23:00 - 6:00这个时间段内才可以访问;
时间格式不是随便配置,而是Spring Cloud Gateway的默认时间格式,采用JDK8里面的格式化:
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT);
String nowTime = dateTimeFormatter.format(ZonedDateTime.now());
System.out.println(nowTime);
到此为止就实现了一个自定义路由谓词工厂,若此时token值不相等,不在允许的访问时间段内,访问就会报404;
处理的顶层接口是WebExceptionHandler
默认实现是DefaultErrorWebExceptionHandler

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

上面的过滤器工厂是执行在指定路由之上,可以称为路由过滤器(或者局部过滤器),而全局过滤器是作用于所有的路由上,对所有的路由进行过滤;
全局过滤器的顶层接口是GlobalFilter ,和GatewayFilter 有一样的接口定义,只不过GlobalFilter 会作用于所有路由;
全局过滤器有执行顺序问题,通过getOrder()方法的返回值决定执行顺序,数值越小越靠前执行;
Spring cloud gateway默认内置了很多全局过滤器,比如:
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;
}
}
实现原理是在全局LoadBalancerClientFilter中进行拦截,然后再该过滤器中依赖LoadBalancerClient loadBalancer,而此负载均衡接口的具体实现是RibbonLoadBalancerClient,即spring cloud gateway已经整合好了ribbon,已经可以实现负载均衡,我们不需要做任何工作,网关对后端微服务的转发就已经具有负载均衡功能;
我们知道,传统的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://store.company.com/dir/page.html

/**
* 配置网关跨域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);
}
}