天天看点

Spring Cloud Alibaba - Gateway

Gateway

Spring Cloud Alibaba - Gateway
Spring Cloud Alibaba - Gateway

底层使用Netty框架,性能大于Zuul

Spring Cloud Alibaba - Gateway

配置gateway模块,一般使用yaml格式:

启动类中添加注解:

启动测试,在这里可能会遇到版本冲突的问题:可以使用ctrl+alt+shift+u ,然后出现如下图所示,红色就是就是证明存在jar包冲突

Spring Cloud Alibaba - Gateway

路由:网关的基本构建组成,它由ID,目标URI,谓词集合和过滤器集合定义,如果集合谓词为true,则匹配路由,否则不匹配;

谓词:这是Java 8函数谓词,输入类型是Spring Framework ServerWebExchange,可以匹配HTTP请求中的所有内容,例如请求头或参数;

过滤器:这些是使用特定工厂构造的Spring Framework GatewayFilter实例,可以在发送给下游请求之前或之后修改请求和响应;

下图从总体上概述了Spring Cloud Gateway的工作方式:

Spring Cloud Alibaba - Gateway

客户端向Spring Cloud Gateway发出请求,如果网关处理程序映射确定请求与路由匹配,则将其发送到网关Web处理程序,该处理程序通过特定于请求的过滤器链运行请求,筛选器由虚线分隔的原因是,筛选器可以在发送代理请求之前和之后运行逻辑,所有“前置”过滤器逻辑均被执行,然后发出代理请求,发出代理请求后,将运行“后”过滤器逻辑;在没有端口的路由中定义URI,HTTP和HTTPS URI的默认端口值分别是80和443

Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分,Spring Cloud Gateway包括许多内置的路由谓词工厂,所有这些谓词都与HTTP请求的不同属性匹配,可以将多个路由谓词工厂结合使用;

总共有11个路由谓词工厂:

\1. The After Route Predicate Factory

\2. The Before Route Predicate Factory

\3. The Between Route Predicate Factory

\4. The Cookie Route Predicate Factory

\5. The Header Route Predicate Factory

\6. The Host Route Predicate Factory

\7. The Method Route Predicate Factory

\8. The Path Route Predicate Factory

\9. The Query Route Predicate Factory

\10. The RemoteAddr Route Predicate Factory

\11. The Weight Route Predicate Factory

After route谓词工厂采用一个参数,即datetime(这是一个Java ZonedDateTime),该谓词匹配在指定日期时间之后发生的请求,以下示例配置了路由后谓词:

Spring Cloud Alibaba - Gateway

这条路由符合2017年1月20日17:42:47时间([America/Denver])之后的任何请求;

时间通过获取:System.out.println(ZonedDateTime.now());

Before路由谓词工厂采用一个参数,即datetime(这是一个Java ZonedDateTime),该谓词匹配在指定日期时间之前发生的请求,下面的示例配置路由之前谓词:

Spring Cloud Alibaba - Gateway

这条路由符合2017年1月20日17:42:47时间([America/Denver])之前的任何请求;

路由谓词之间的工厂使用两个参数datetime1和datetime2,它们是java ZonedDateTime对象,该谓词匹配在datetime1之后和datetime2之前发生的请求,datetime2参数必须在datetime1之后,以下示例配置了路由之间的谓词:

Spring Cloud Alibaba - Gateway

该路线与2017年1月20日山区时间(丹佛)之后和2017年1月21日17:42山区时间(丹佛)之前的任何请求相匹配,这对于维护时段可能很有用;

Cookie路由谓词工厂采用两个参数,即cookie名称和一个regexp(这是Java正则表达式),该谓词匹配具有给定名称且其值与正则表达式匹配的cookie,以下示例配置Cookie路由谓词工厂:

Spring Cloud Alibaba - Gateway

此路由匹配具有名为Chocolate的cookie的请求,该cookie的值与ch.p正则表达式匹配;

举例:curl http://192.168.0.104/index --cookie token=123456

header 路由谓词工厂使用两个参数,header 名称和一个regexp(这是Java正则表达式),该谓词与具有给定名称的header 匹配,该header 的值与正则表达式匹配,以下示例配置标头路由谓词:

Spring Cloud Alibaba - Gateway

如果请求具有名为X-Request-Id的标头,且其值与\ d +正则表达式匹配(即,其值为一个或多个数字),则此路由匹配;

举例:curl http://192.168.0.104/index --header "X-Request-Id:19228"

host路由谓词工厂使用一个参数:主机名模式列表,以下示例配置主机路由谓词:

Spring Cloud Alibaba - Gateway

还支持URI模板变量(例如{sub} .myhost.org),如果请求的主机标头的值为www.somehost.org或beta.somehost.org或www.anotherhost.org,则此路由匹配;

方法路由谓词工厂使用方法参数,该参数是一个或多个参数:要匹配的HTTP方法,以下示例配置方法route谓词:

Spring Cloud Alibaba - Gateway

如果请求方法是GET或POST,则此路由匹配;

路径路由谓词工厂使用两个参数:Spring PathMatcher模式列表和一个称为matchOptionalTrailingSeparator的可选标志,以下示例配置路径路由谓词:

Spring Cloud Alibaba - Gateway

如果请求路径为例如/red/1或/red/blue或/blue/green,则此路由匹配;

查询路由谓词工厂采用两个参数:必需的参数和可选的regexp(这是Java正则表达式),以下示例配置查询路由谓词:

Spring Cloud Alibaba - Gateway

如果请求包含green查询参数,则前面的路由匹配;

Spring Cloud Alibaba - Gateway

如果请求包含值与gree匹配的red查询参数,则上述路由匹配;

RemoteAddr路由谓词工厂使用源列表(最小大小为1),这些源是标记(IPv4或IPv6)字符串,例如192.168.0.1/16(其中192.168.0.1是IP地址,而16是子网掩码)),下面的示例配置RemoteAddr路由谓词:

Spring Cloud Alibaba - Gateway

如果请求的远程地址是例如192.168.1.10,则此路由匹配;

权重路由谓词工厂采用两个参数:group和weight(一个int),权重是按组计算的,以下示例配置权重路由谓词:

Spring Cloud Alibaba - Gateway

这条路由会将约80%的流量转发至weight_high.org,并将约20%的流量转发至weight_low.org;

路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应,Spring Cloud Gateway包括许多内置的GatewayFilter工厂;

Spring Cloud Alibaba - Gateway

总共有31个GatewayFilter工厂:

\1. The AddRequestHeader GatewayFilter Factory

\2. The AddRequestParameter GatewayFilter Factory

\3. The AddResponseHeader GatewayFilter Factory

\4. The DedupeResponseHeader GatewayFilter Factory

\5. The Hystrix GatewayFilter Factory

\6. Spring Cloud CircuitBreaker GatewayFilter Factory

\7. The FallbackHeaders GatewayFilter Factory

\8. The MapRequestHeader GatewayFilter Factory

\9. The PrefixPath GatewayFilter Factory

\10. The PreserveHostHeader GatewayFilter Factory

\11. The RequestRateLimiter GatewayFilter Factory

\12. The RedirectTo GatewayFilter Factory

\13. The RemoveRequestHeader GatewayFilter Factory

\14. RemoveResponseHeader GatewayFilter Factory

\15. The RemoveRequestParameter GatewayFilter Factory

\16. The RewritePath GatewayFilter Factory

\17. RewriteLocationResponseHeader GatewayFilter Factory

\18. The RewriteResponseHeader GatewayFilter Factory

\19. The SaveSession GatewayFilter Factory

\20. The SecureHeaders GatewayFilter Factory

\21. The SetPath GatewayFilter Factory

\22. The SetRequestHeader GatewayFilter Factory

\23. The SetResponseHeader GatewayFilter Factory

\24. The SetStatus GatewayFilter Factory

\25. The StripPrefix GatewayFilter Factory

\26. The Retry GatewayFilter Factory

\27. The RequestSize GatewayFilter Factory

\28. The SetRequestHost GatewayFilter Factory

\29. Modify a Request Body GatewayFilter Factory

\30. Modify a Response Body GatewayFilter Factory

\31. Default Filters

Spring Cloud Gateway内置了一系列的路由谓词工厂,但是如果这些内置的路由谓词工厂不能满足业务需求的话,可以自定义路由谓词工厂来实现特定的需求;

下面列举两个例子:

1、要求请求必须携带一个token,并且token值等于指定的值,才能访问;

2、要求某个服务的用户只允许在23:00 - 6:00这个时间段内才可以访问;

自定义谓词具体步骤:

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

(2)定义一个路由谓词工厂;

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

(3)在配置文件中启用该路由谓词工厂,即配置一个Token=123456;

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

<code>DateTimeFormatter dateTimeFormatter = DateTimeFormatter.*ofLocalizedTime*(FormatStyle.*SHORT*); String nowTime = dateTimeFormatter.format(ZonedDateTime.*now*()); System.*out*.println(nowTime);</code>

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

以Token为例:

配置类:

自定义路由谓词工厂:

如果谓词不匹配时,处理返回404页面显然不合规范。需要我们对404进行处理

处理的顶层接口是WebExceptionHandler

默认实现是DefaultErrorWebExceptionHandler

Spring Cloud Alibaba - Gateway

我们需要覆盖它的默认实现DefaultErrorWebExceptionHandler,覆盖里面的方法getRoutingFunction,getHttpStatus,在方法里面编写我们想要返回的结果

实现类:

除此之外,还需要写一个配置类,添加相关配置,使得404时,将相关信息给到上面编写的处理异常类中,并将该异常类返回。

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

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

全局过滤器的顶层接口是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

当然我们也可以自定义全局过滤器

一经实现,就生效。只要满足实现要求,就实现全局过滤。

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

网关集成Sentinel是为了流控熔断降级,具体集成整合步骤如下:

1、添加依赖;

*

2、在gateway配置文件中添加sentinel控制台配置;

3、写代码,在spring容器中配置一个Sentinel的全局过滤器;

4、可以进行测试;

在Gateway的配置类(GatewayConfiguration)中,注入一个实例限流时返回BlockRequestHandler

(1)配置依赖;

(2)暂时不需要配置;

(3)写代码;

(4)配置SPI;

resources\META-INF\services\com.alibaba.csp.sentinel.init.InitFunc

放入第三步类的路径(copy reference)

1、添加sentinel-datasource-nacos依赖;

2、application.properties配置持久化数据源;

3、在nacos配置中心配置流控规则(每个route都可以配置逗号隔开):

Spring Cloud Alibaba - Gateway

(1)根据自动装配spring-cloud-gateway-core.jar的spring.factories;

(2)GatewayClassPathWarningAutoConfiguration检查前端控制器;

(3)网关自动配置GatewayAutoConfiguration;

(4)RoutePredicateHandlerMapping.getHandlerInternal(...)获取Route;

(5)执行FilteringWebHandler

我们知道,传统的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

URL

是否同源

原因

http://store.company.com/dir2/other.html

http://store.company.com/dir/inner/another.html

https://store.company.com/secure.html

协议不同

http://store.company.com:81/dir/etc.html

端口不同

http://news.company.com/dir/other.html

host不同

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