热门关键词:世界杯买球  
当前位置:首页 > 企业新闻
【世界杯买球】Spring cloud alibaba解说《五》:Gateway——服务网关
2023-09-06 [24362]
本文摘要:网关简介大家都都知道在微服务架构中,一个系统会被拆分为许多个微服务。

世界杯买球

网关简介大家都都知道在微服务架构中,一个系统会被拆分为许多个微服务。那么作为客户端要如何去挪用这么多的微服务呢?如果没有网关的存在,我们只能在客户端记载每个微服务的地址,然后划分去挪用这样的架构,会存在着诸多的问题:客户端多次请求差别的微服务,增加客户端代码或设置编写的庞大性认证庞大,每个服务都需要独立认证。

存在跨域请求,在一定场景下处置惩罚相对庞大。上面的这些问题可以借助API网关来解决。所谓的API网关,就是指系统的统一入口,它封装了应用法式的内部结构,为客户端提供统一服务一些与业务自己功效无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、路由转发等等。

添加上API网关之后,系统的架构图酿成了如下所示我们也可以视察下,我们现在的整体架构图:在业界比力盛行的网关,有下面这些:Ngnix+lua:使用nginx的反向署理和负载平衡可实现对api服务器的负载平衡及高可用,lua是一种剧本语言,可以来编写一些简朴的逻辑, nginx支持lua剧本Kong:基于Nginx+Lua开发,性能高,稳定,有多个可用的插件(限流、鉴权等等)可以开箱即用。问题:只支持Http协议;二次开发,自由扩展难题;提供治理API,缺乏更易用的管控、设置方式。Zuul :Netflflflflix开源的网关,功效富厚,使用JAVA开发,易于二次开发 问题:缺乏管控,无法动态设置;依赖组件较多;处置惩罚Http请求依赖的是Web容器,性能不如NginxSpring Cloud Gateway:Spring公司为了替换Zuul而开发的网关服务,将在下面详细先容。

注意:SpringCloud alibaba技术栈中并没有提供自己的网关,我们可以接纳Spring Cloud Gateway来做网关Gateway简介Spring Cloud Gateway是Spring公司基于Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简朴有效的统一的 API 路由治理方式。它的目的是替代NetflflflflixZuul,其不仅提供统一的路由方式,而且基于 Filter 链的方式提供了网关基本的功效,例如:宁静,监控和限流。优点:性能强劲:是第一代网关Zuul的1.6倍功效强大:内置了许多实用的功效,例如转发、监控、限流等设计优雅,容易扩展缺点:其实现依赖Netty与WebFlux,不是传统的Servlet编程模型,学习成本高不能将其部署在Tomcat、Jetty等Servlet容器里,只能打成jar包执行需要Spring Boot 2.0及以上的版本,才支持Gateway快速入门要求: 通过浏览器会见api网关,然后通过网关将请求转发到商品微服务基础版第1步:建立一个 api-gateway 的模块,导入相关依赖<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springcloud-alibaba</artifactId><groupId>com.itheima</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>api-gateway</artifactId><dependencies><!--gateway网关--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency></dependencies></project>第2步: 建立主类package com.itheima;@SpringBootApplicationpublic class GatewayApplication {public static void main(String[] args) {SpringApplication.run(GatewayApplication.class, args);}}第3步: 添加设置文件server:port: 7000spring:application:name: api-gatewaycloud:gateway:routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]\- id: product_route # 当前路由的标识, 要求唯一uri: http://localhost:8081 # 请求要转发到的地址order: 1 # 路由的优先级,数字越小级别越高predicates: # 断言(就是路由转发要满足的条件)\- Path=/product-serv/** # 当请求路径满足Path指定的规则时,才举行路由转发filters: # 过滤器,请求在通报历程中可以通过过滤器对其举行一定的修改\- StripPrefix=1 # 转发之前去掉1层路径第4步: 启动项目, 并通过网关去会见微服务增强版第1步:加入nacos依赖<!--nacos客户端--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>第2步:在主类上添加注解@SpringBootApplication@EnableDiscoveryClientpublic class ApiGatewayApplication {public static void main(String[] args) {SpringApplication.run(ApiGatewayApplication.class, args);}}第3步:修改设置文件server:port: 7000spring:application:name: api-gatewaycloud:nacos:discovery:server-addr: 127.0.0.1:8848gateway:discovery:locator:enabled: true # 让gateway可以发现nacos中的微服务routes:\- id: product_routeuri: lb://service-product # lb指的是从nacos中根据名称获取微服务,并遵循负载平衡计谋predicates:\- Path=/product-serv/**filters:\- StripPrefix=1第4步:测试简写版第1步: 去掉关于路由的设置server:port: 7000spring:application:name: gatewaycloud:nacos:discovery:server-addr: 127.0.0.1:8848gateway:discovery:locator:enabled: true第2步: 启动项目,并通过网关去会见微服务这时候,就发现只要根据网关地址微服务接口的花样去会见,就可以获得乐成响应。Gateway焦点架构 基本观点路由(Route) 是 gateway 中最基本的组件之一,表现一个详细的路由信息载体。

主要界说了下面的几个信息:id,路由标识符,区别于其他 Route。uri,路由指向的目的地 uri,即客户端请求最终被转发到的微服务。order,用于多个 Route 之间的排序,数值越小排序越靠前,匹配优先级越高。

predicate,断言的作用是举行条件判断,只有断言都返回真,才会真正的执行路由。fifififilter,过滤器用于修改请求和响应信息。执行流程执行流程大要如下:1. Gateway Client向Gateway Server发送请求2. 请求首先会被HttpWebHandlerAdapter举行提取组装成网关上下文3. 然后网关的上下文会通报到DispatcherHandler,它卖力将请求分发给RoutePredicateHandlerMapping4. RoutePredicateHandlerMapping卖力路由查找,并凭据路由断言判断路由是否可用5. 如果过断言乐成,由FilteringWebHandler建立过滤器链并挪用6. 请求会一次经由PreFilter--微服务-PostFilter的方法,最终返回响应断言Predicate(断言, 谓词) 用于举行条件判断,只有断言都返回真,才会真正的执行路由。断言就是说: 在 什么条件下 才气举行路由转发 内置路由断言工厂SpringCloud Gateway包罗许多内置的断言工厂,所有这些断言都与HTTP请求的差别属性匹配。

详细如下:基于Datetime类型的断言工厂此类型的断言凭据时间做判断,主要有三个:AfterRoutePredicateFactory: 吸收一个日期参数,判断请求日期是否晚于指定日期BeforeRoutePredicateFactory: 吸收一个日期参数,判断请求日期是否早于指定日期BetweenRoutePredicateFactory: 吸收两个日期参数,判断请求日期是否在指定时间段内-After=2019-12-31T23:59:59.789+08:00[Asia/Shanghai]基于远程地址的断言工厂 RemoteAddrRoutePredicateFactory:吸收一个IP地址段,判断请求主机地址是否在地址段中-RemoteAddr=192.168.1.1/24基于Cookie的断言工厂CookieRoutePredicateFactory:吸收两个参数,cookie 名字和一个正则表达式。判断请求cookie是否具有给命名称且值与正则表达式匹配。-Cookie=chocolate, ch.基于Header的断言工厂HeaderRoutePredicateFactory:吸收两个参数,标题名称和正则表达式。判断请求Header是否具有给命名称且值与正则表达式匹配。

-Header=X-Request-Id, \d+基于Host的断言工厂HostRoutePredicateFactory:吸收一个参数,主机名模式。判断请求的Host是否满足匹配规则。-Host=**.testhost.org基于Method请求方法的断言工厂MethodRoutePredicateFactory:吸收一个参数,判断请求类型是否跟指定的类型匹配。

-Method=GET基于Path请求路径的断言工厂PathRoutePredicateFactory:吸收一个参数,判断请求的URI部门是否满足路径规则。-Path=/foo/{segment}基于Query请求参数的断言工厂QueryRoutePredicateFactory :吸收两个参数,请求param和正则表达式, 判断请求参数是否具有给命名称且值与正则表达式匹配。

-Query=baz, ba.基于路由权重的断言工厂WeightRoutePredicateFactory:吸收一个[组名,权重], 然后对于同一个组内的路由根据权重转发routes:-id: weight_route1 uri: host1 predicates:-Path=/product/**-Weight=group3, 1-id: weight_route2 uri: host2 predicates:-Path=/product/**-Weight= group3, 9内置路由断言工厂的使用接下来我们验证几个内置断言的使用:server:port: 7000spring:application:name: api-gatewaycloud:nacos:discovery:server-addr: 127.0.0.1:8848gateway:discovery:locator:enabled: trueroutes:\- id: product_routeuri: lb://service-productpredicates:\- Path=/product-serv/**\- Before=2019-11-28T00:00:00.000+08:00 #限制请求时间在2019-11-28之前\- Method=POST #限制请求方式为POSTfilters:\- StripPrefix=1自界说路由断言工厂我们来设定一个场景: 假设我们的应用仅仅让age在(min,max)之间的人来会见。第1步:在设置文件中,添加一个Age的断言设置spring:application:name: api-gatewaycloud:nacos:discovery:server-addr: 127.0.0.1:8848gateway:discovery:locator:enabled: trueroutes:\- id: product-routeuri: lb://service-productpredicates:\- Path=/product-serv/**\- Age=18,60 # 限制年事只有在18到60岁之间的人能会见filters:\- StripPrefix=1第2步:自界说一个断言工厂, 实现断言方法package com.itheima.predicates;//泛型 用于吸收一个设置类,设置类用于吸收中设置文件中的设置@Componentpublic class AgeRoutePredicateFactoryextends AbstractRoutePredicateFactory<AgeRoutePredicateFactory.Config> {public AgeRoutePredicateFactory() {super(AgeRoutePredicateFactory.Config.class);}//用于从设置文件中获取参数值赋值到设置类中的属性上@Overridepublic List<String> shortcutFieldOrder() {//这里的顺序要跟设置文件中的参数顺序一致return Arrays.asList("minAge", "maxAge");}//断言@Overridepublic Predicate<ServerWebExchange> apply(AgeRoutePredicateFactory.Configconfig) {return new Predicate<ServerWebExchange>() {@Overridepublic boolean test(ServerWebExchange serverWebExchange) {//从serverWebExchange获取传入的参数String ageStr =serverWebExchange.getRequest().getQueryParams().getFirst("age");if (StringUtils.isNotEmpty(ageStr)) {int age = Integer.parseInt(ageStr);return age > config.getMinAge() && age < config.getMaxAge();}return true;}};}}//自界说一个设置类, 用于吸收设置文件中的参数@Dataclass Config {private int minAge;private int maxAge;}第4步:启动测试\#测试发现当age在(20,60)可以会见,其它规模不能会见http://localhost:7000/product-serv/product/1?age=30http://localhost:7000/product-serv/product/1?age=10过滤器三个知识点:1. 作用: 过滤器就是在请求的通报历程中,对请求和响应做一些手脚2. 生命周期: Pre Post3. 分类: 局部过滤器(作用在某一个路由上) 全局过滤器(作用全部路由上)在Gateway中, Filter的生命周期只有两个:“pre” 和 “post”。

PRE: 这种过滤器在请求被路由之前挪用。我们可使用这种过滤器实现身份验证、在集群中选择请求的微服务、记载调试信息等。POST:这种过滤器在路由到微服务以后执行。

这种过滤器可用来为响应添加尺度的HTTPHeader、收集统计信息和指标、将响应从微服务发送给客户端等。Gateway 的Filter从作用规模可分为两种: GatewayFilter与GlobalFilter。GatewayFilter:应用到单个路由或者一个分组的路由上。

世界杯买球

GlobalFilter:应用到所有的路由上。局部过滤器局部过滤器是针对单个路由的过滤器。

内置局部过滤器在SpringCloud Gateway中内置了许多差别类型的网关路由过滤器。详细如下:内置局部过滤器的使用server:port: 7000spring:application:name: api-gatewaycloud:nacos:discovery:server-addr: localhost:8848gateway:discovery:locator:enabled: trueroutes:\- id: product_routeuri: lb://service-productorder: 1predicates:\- Path=/product-serv/**filters:\- StripPrefix=1\- SetStatus=2000 # 修改返回状态自界说局部过滤第1步:在设置文件中,添加一个Log的过滤器设置spring:application:name: gatewaycloud:nacos:discovery:server-addr: 127.0.0.1:8848gateway:discovery:locator:enabled: trueroutes:\- id: consumerorder: -1uri: lb://consumerpredicates:\- Path=/consumer-serv/**filters:\- StripPrefix=1\- Log=true,false # 控制日志是否开启第2步:自界说一个过滤器工厂,实现方法//自界说局部过滤器@Componentpublic class LogGatewayFilterFactoryextends AbstractGatewayFilterFactory<LogGatewayFilterFactory.Config> {//结构函数public LogGatewayFilterFactory() {super(LogGatewayFilterFactory.Config.class);}//读取设置文件中的参数 赋值到 设置类中@Overridepublic List<String> shortcutFieldOrder() {return Arrays.asList("consoleLog", "cacheLog");}//过滤器逻辑@Overridepublic GatewayFilter apply(LogGatewayFilterFactory.Config config) {return new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange,GatewayFilterChain chain) {if (config.isCacheLog()) {System.out.println("cacheLog已经开启了....");}if (config.isConsoleLog()) {System.out.println("consoleLog已经开启了....");}return chain.filter(exchange);}};}//设置类 吸收设置参数@Data@NoArgsConstructorpublic static class Config {private boolean consoleLog;private boolean cacheLog;}第3步:启动测试全局过滤器全局过滤器作用于所有路由, 无需设置。通过全局过滤器可以实现对权限的统一校验,宁静性验证等功效。内置全局过滤器SpringCloud Gateway内部也是通过一系列的内置全局过滤器对整个路由转发举行处置惩罚如下:自界说全局过滤器内置的过滤器已经可以完成大部门的功效,可是对于企业开发的一些业务功效处置惩罚,还是需要我们自己编写过滤器来实现的,那么我们一起通过代码的形式自界说一个过滤器,去完成统一的权限校验。

开发中的鉴权逻辑:当客户端第一次请求服务时,服务端对用户举行信息认证(登录)认证通过,将用户信息举行加密形成token,返回给客户端,作为登录凭证以后每次请求,客户端都携带认证的token服务端对token举行解密,判断是否有效如上图,对于验证用户是否已经登录鉴权的历程可以在网关统一磨练。磨练的尺度就是请求中是否携带token凭证以及token的正确性。下面的我们自界说一个GlobalFilter,去校验所有请求的请求参数中是否包罗“token”,如何不包罗请求参数“token”则不转发路由,否则执行正常的逻辑。

package com.itheima.filters;//自界说全局过滤器需要实现GlobalFilter和Ordered接口@Componentpublic class AuthGlobalFilter implements GlobalFilter, Ordered {//完成判断逻辑@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChainchain) {String token = exchange.getRequest().getQueryParams().getFirst("token");if (StringUtils.isBlank(token)) {System.out.println("鉴权失败");exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);return exchange.getResponse().setComplete();}//挪用chain.filter继续向下游执行return chain.filter(exchange);}//顺序,数值越小,优先级越高@Overridepublic int getOrder() {return 0;}}网关限流网关是所有请求的公共入口,所以可以在网关举行限流,而且限流的方式也许多,我们本次接纳前面学过的Sentinel组件来实现网关的限流。Sentinel支持对SpringCloud Gateway、Zuul等主流网关举行限流。从1.6.0版本开始,Sentinel提供了SpringCloud Gateway的适配模块,可以提供两种资源维度的限流:route维度:即在Spring设置文件中设置的路由条目,资源名为对应的routeId自界说API维度:用户可以使用Sentinel提供的API来自界说一些API分组1 导入依赖<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-spring-cloud-gateway-adapter</artifactId></dependency>2 编写设置类基于Sentinel 的Gateway限流是通过其提供的Filter来完成的,使用时只需注入对应的SentinelGatewayFilter实例以及 SentinelGatewayBlockExceptionHandler 实例即可。

@Configurationpublic class GatewayConfiguration {private final List<ViewResolver> viewResolvers;private finalServerCodecConfigurer serverCodecConfigurer;public GatewayConfiguration(ObjectProvider<List<ViewResolver>>viewResolversProvider,ServerCodecConfigurer serverCodecConfigurer) {this.viewResolvers =viewResolversProvider.getIfAvailable(Collections::emptyList);this.serverCodecConfigurer = serverCodecConfigurer;}// 初始化一个限流的过滤器@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public GlobalFilter sentinelGatewayFilter() {return new SentinelGatewayFilter();}// 设置初始化的限流参数@PostConstructpublic void initGatewayRules() {Set<GatewayFlowRule> rules = new HashSet<>();rules.add(new GatewayFlowRule("product_route") //资源名称,对应路由id.setCount(1) // 限流阈值.setIntervalSec(1) // 统计时间窗口,单元是秒,默认是 1 秒);GatewayRuleManager.loadRules(rules);}// 设置限流的异常处置惩罚器@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public SentinelGatewayBlockExceptionHandlersentinelGatewayBlockExceptionHandler() {return new SentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer);}// 自界说限流异常页面@PostConstructpublic void initBlockHandlers() {BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {public Mono<ServerResponse> handleRequest(ServerWebExchangeserverWebExchange, Throwable throwable) {Map map = new HashMap<>();map.put("code", 0);map.put("message", "接口被限流了");returnServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON_UTF8).body(BodyInserters.fromObject(map));}};GatewayCallbackManager.setBlockHandler(blockRequestHandler);}}3 测试在一秒钟内多次会见http://localhost:7000/product-serv/product/1就可以看到限流启作用了。4 自界说API分组自界说API分组是一种更细粒度的限流规则界说/**\* 设置初始化的限流参数*/@PostConstructpublic void initGatewayRules() {Set<GatewayFlowRule> rules = new HashSet<>();rules.add(newGatewayFlowRule("product_api1").setCount(1).setIntervalSec(1));rules.add(newGatewayFlowRule("product_api2").setCount(1).setIntervalSec(1));GatewayRuleManager.loadRules(rules);}//自界说API分组@PostConstructprivate void initCustomizedApis() {Set<ApiDefinition> definitions = new HashSet<>();ApiDefinition api1 = new ApiDefinition("product_api1").setPredicateItems(new HashSet<ApiPredicateItem>() {{// 以/product-serv/product/api1 开头的请求add(new ApiPathPredicateItem().setPattern("/product-serv/product/api1/**").setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));}});ApiDefinition api2 = new ApiDefinition("product_api2").setPredicateItems(new HashSet<ApiPredicateItem>() {{// 以/product-serv/product/api2/demo1 完成的url路径匹配add(new ApiPathPredicateItem().setPattern("/product-serv/product/api2/demo1"));}});definitions.add(api1);definitions.add(api2);GatewayApiDefinitionManager.loadApiDefinitions(definitions);}。


本文关键词:世界杯买球

本文来源:世界杯买球-www.iliulei.com