什么是学习目标网关?它是做什么的?网关中的断言使用网关中的过滤器使用网关中的路由使用网关1.1的概念简单来说,网关是一个网络连接到另一个网络的“网关”。如下图所示,当我们的局域网(LAN)想要访问外网的数据时,需要通过路由器进行转发,这里的路由器就充当了网关的角色。
1.2网关的作用网关的作用是实现不同网络之间的互联,同时也可以实现不同通信协议、数据格式和其他系统之间的转发。今天我们要讲解的是关口,也是关口的一种。我们称之为应用网关,也称为API网关。为什么需要API网关?我们还得从架构的演进过程来解释:前面说过,在微服务架构中,每个微服务都是一个独立的组件,这些组件被调用到H5、Android、IOS等客户端程序中通过Rest API风格的接口。(移动互联网时代,为了尽快迭代)。在一个UI界面中,通常会显示很多数据,这些数据可能来自不同的微服务。例如,在电子商务系统中,需要执行订单请求。
从营销服务查询促销信息,从会员服务查询会员等级和会员积分,从商品服务查询商品详情,调用订单服务下单。1.3早期微服务架构出现的背景,面对这样的情况,出现了如下图所示的调用模式。
在这种通话方式中,不难发现更多的问题:
客户端与内部微服务的耦合度较高,任何一方发生变化,都会影响到客户端需要维护的内部微服务的地址等对方的信息。如果微服务地址发生变化,也会影响客户端的通信。客户端需要调用多个接口请求,导致来自服务器的请求过多。这种方式存在很多问题,所以一般我们会在客户端和微服务之间引入BFF层(即Backend For Frontend),即服务器在设计API时会考虑使用Frontend,直接在服务器上处理业务逻辑,也就是用户体验适配器。如下图所示,BFF层为客户端提供统一的聚合服务,我们可以在BFF层为不同的客户端或者不同的服务提供更加友好统一的客户端。
引入BFF层的优点是
客户端和内部微服务之间没有耦合,这样两端的变化可以独立。当APP上有新的需求时,可以通过BFF层进行评估,从而降低后端团队的沟通成本。如果后端微服务设计得足够好,很多需求都可以在BFF层解决。然而,这种方式仍然存在一些问题。当客户端发起进入BFF层的请求时,需要考虑安全问题,如认证、限流等。而且每个BFF模块都需要写这些函数,增加了很多重复代码。而且维护非常不灵活,导致开发效率下降。所以引入了API网关,整体结构如下图所示。
网关是微服务架构不可或缺的一部分。作为微服务架构的唯一入口,它将所有请求转发到后端对应的微服务,同时可以将所有微服务的通用功能集中在网关上,而不是全部在每个微服务上实现。
认证授权限流版本控制缓存统一日志。同时,添加网关后,每个BFF模块的横切功能都被剥离到网关中。BFF模块开发人员只需要关注业务逻辑的交付。通用开源网关
Opensty (Nginx Lua) Zuul是spring云生态下提供的网关服务,性能比较低。Spring云网关是Spring团队开发的高性能网关1.4。Spring Cloud Gateway是Spring官方团队开发的API网关技术,其目的是替代Zuul为微服务提供一个简单高效的API网关。一般来说,春队不会重复造轮子。它为什么要开发春云网关?有几个原因。
Zuul1.x使用传统的每连接一个线程的方法来处理请求,也就是说,对于每个请求,都会专门分配一个线程来处理这个请求,直到请求完成,线程才会被释放。一旦后台服务器响应慢,这个线程就会被阻塞,所以性能不是很好。Zuul本身的一些性能问题并不适合高并发场景。虽然网飞后来决定开发高性能版本的Zuul 2.x,但Zuul 2.x的发布时间一直不确定。虽然Zuul 2.x已经发布并且开源,但是春云并不打算集成。云网关是依托Spring Boot 2.0、Spring WebFlux、Project Reactor等技术开发的网关。它不仅提供了路由请求的统一方式,还提供了基于过滤链的网关的最基本功能。1.5网关的基本概念Spring云网关的基本工作原理如下图所示。客户端向Spring Cloud Gateway发送请求。然后在网关处理程序映射中找到与请求匹配的路由,并将其发送给网关Web处理程序。Handler通过指定的过滤器链将请求发送到我们实际的服务执行业务逻辑,然后返回。过滤器由虚线分隔,因为过滤器可以在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。
“pre”类型的过滤器可用于参数验证、权限验证、流量监控、日志输出、协议转换等。“post”类型的过滤器可用于修改响应内容、响应标题、日志输出、流量监控等。它起着非常重要的作用。Spring Cloud Gateway中有三个重要的对象,即:
路由是网关的基本元素,由ID、目标URI、断言和过滤器组成。当当前请求到达网关时,它将通过网关处理程序映射来匹配基于断言的路由。当断言为真时,它将匹配路由以转发谓词断言。学过java8的同学应该知道这个函数。它可以让开发人员匹配HTTP请求中的元素。一旦匹配为真,就意味着它与转发过滤器的适当路由相匹配。它可以在请求发送前后做一些业务处理,比如授权、嵌入、限流等。的具体工作原理如下图所示:
其总体工作原理如下。其中,谓词是我们的匹配条件;另一方面,过滤器可以理解为一个无所不能的拦截器。有了这两个元素和目标uri,就可以实现特定的路由。客户端向Spring Cloud Gateway发送请求。如果请求匹配网关程序定义的路由,请求将被发送到网关Web处理程序,处理程序将运行特定的请求过滤器链。过滤器被虚线分隔的原因是过滤器可能在发送代理请求之前和之后执行逻辑。首先执行所有前置过滤逻辑,然后执行代理请求;代理完成请求后,执行后过滤器逻辑。
第二章谓词应用我们通过一些案例演示来初步了解一下Spring Cloug Gateway.1。1.在以上的基础上,整个项目被复制并重命名为gateway-**2。在上述框架的基础上,修改用户项目中的HelloController和用户控制器。
@ RestControllerpublic class hello controller { @ auto wired OrderServiceClient OrderServiceClient;@Value(‘${server.port} ‘)专用(同Internationalorganizations)国际组织端口;@ get mapping(‘/hello/{ name } ‘)public String get(@ path variable(‘ name ‘)String name){ String result=’ ‘;//同步result=new HelloCommand(name,orderServiceClient).执行();’返回’当前用户端口为:’端口,结果为:’结果;} } @ RestControllerpublic类用户控制器{ @ auto wired OrderServiceClient OrderServiceClient;@Value(‘${server.port} ‘)专用(同Internationalorganizations)国际组织端口;@ hystrix命令(命令属性={ @ HystrixProperty(name=’断路器。requestvolumethreshold ‘,value=’10 ‘),@ HystrixProperty(name=’断路器。sleepwindimillseconds ‘,value=’5000 ‘),@ HystrixProperty(name=’断路器。errorthreshold percentage ‘,value=’50 ‘),},fallback method=’ fallback ‘)@ get mapping(‘/get/{ num } ‘)公共字符串get(@PathVariable(‘num当前用户端口为:’端口,结果为:正常访问;}返回’当前用户端口为:’端口,结果为:’ orderserviceclient。订单列表(数量);}公共字符串回退(整数){ return ‘触发降级;}}并分别开启两个用户项目,端口为8080和8081;开启两个命令项目,端口分别为8088和80993.创建新的跳羚项目网关-公共4。配置砰的一声
可扩展标记语言版本=’1.0 ‘编码=’ UTF-8 ‘ 4。0 .0 eclipse 2019-demo com。示例1.0-快照com。示例网关-通用演示Spring boot 1.8 org。Spring框架。启动弹簧-启动-测试。Spring框架。云之春-云之星-网关组织。Spring框架。云泉-云泉-启动器-网飞-尤里卡-客户端5 .配置yml,如果用的是玉米片,一般这些配置可以写在高洛里面
服务器:端口: 9527春天:应用程序:名称:网关云:网关:路由: #路由的ID,没有固定规则但要求唯一,建议配合服务名- id: getUser #匹配后提供服务的路由地址uri : http://本地主机:8080 #断言,路径相匹配的进行路由谓词s :-Path=/get/* *-id : say hello uri : http://localhost :8081谓词s :-Path=/hello/* *-id : hei hei uri : https://www.baidu.com/谓词s :-Path=/hei hei/* * filters :-strip前缀=1 #去掉地址中的第一部分- StripPrefix=2 #去掉地址中的第二部分尤里卡:实例:主机名:网关-9527客户端:服务-URL :向eureka注册:真实获取-注册表:真实默认区域http://127。0 .0 .1:8761/尤里卡6 .启动类
@ spring boot application @ EnableDiscoveryClientpublic类gatewayconapplication { public static void main(String[]args){ spring application。运行(gatewayconapplication。class,args);} }7.测试
2.1谓词规则上述案例中,我们使用了门中的小路匹配规则,也就是根据请求的上呼吸道感染地址,使用前缀匹配规则完成请求地址的匹配。
门内置了是多种述语匹配规则,具体如下图所示
查询断言询问路由断言工厂接收两个参数,一个必需的参数和一个可选的正则表达式。
春天:云:网关:路由:-id :查询_路由uri : https://www.baidu.com/预测: – Query=name,eclipse2019 .*帅如果请求包含一个名字的参数,值是eclipse2019开头,齐帅结尾,则此路由将匹配。第二个参数是正则表达式。测试链接:http://localhost :9527/name=feichangshuaiqieclipse 2019
方法断言方法路由断言工厂接收一个参数,即要匹配的超文本传送协议方法。
spring :云:网关:路由:-id :方法_路由uri : https://www.douyu.com/预测: – Method=GET 2.1.3标题断言页眉路由断言工厂接收两个参数,分别是请求头名称和正则表达式。
spring : cloud : gateway : routes :-Id : Header _ route uri : https://www.douyin.com/predicates :-Header=X-Request-Id,\如果d请求中有一个名为X-Request-Id的请求头,并且它的值与\d正则表达式匹配(值是一个或多个数字),那么这个路由匹配。
2.1.4 Cookie断言spring : cloud : gateway 3360 routes :-id : Cookie _ route uri 3360 https://www.huya.com/预测3360-cookie=name,Eclipse 2019 through postman,访问http://localhost:9527并在请求中携带cookie name=eclipse2019。可以匹配路由转发。
2.2除了使用官方断言工厂,如果我们有个性化的需求,也可以实现自定义谓词。自定义路由断言工厂需要继承AbstractRoutePredicateFactory类,并覆盖apply方法的逻辑。在apply方法中,可以通过exchange.getRequest()获取ServerHttpRequest对象,这样就可以得到请求的参数、请求方法、请求等信息。apply方法的参数是用户自定义的配置类,使用时进行配置,在apply方法中直接获取并使用。
名称需要以RoutePredicateFactory结尾,比如AuthRoutePredicateFactory,那么Auth就是这个路由断言工厂在使用时的名称。代码如下所示。
1.自定义AuthRoutePredicateFactory
@Componentpublic类AuthRoutePredicateFactory扩展AbstractRoutePredicateFactory { Logger Logger=Logger factory . get Logger(AuthRoutePredicateFactory . class);公共静态最终字符串NAME _ KEY=’ namepublic AuthRoutePredicateFactory(){ super(config . class);} @ Override public List shortcutfield order(){ return arrays . as List(NAME _ KEY);} @Override公共谓词apply(Config Config){ logger . info(‘ AuthRoutePredicateFactory Start ‘);//只要请求头包含yml配置的授权,就允许匹配路由返回Exchange-{ http headers=Exchange . get request()。get headers();list header=headers . get(config . getname());返回header . size()0;};}公共静态类配置{私有字符串名称;公共字符串getName(){ return name;} public void set name(String name){ this . name=name;} }}2.在配置文件中添加以下配置信息
-id : define _ routeruri 3360 https://www.baidu.com预测3360-path=/define/* *-auth=authorization filters 3360-strip prefix=13。访问测试
访问邮差测试中的URL :http://localhost 33609527/define/1:表头加授权不加授权的效果。第3章过滤器应用过滤器是网关的核心,起着请求过滤的作用。在网关中,请求将被前置和后置过滤。pre表示在请求进来之前,post表示在请求被处理之后返回给客户机之前。
Pred过滤器可以进行授权和认证、流量监控、协议转换等。后置过滤器可以修改响应内容、输出日志等。下图显示了通过过滤器处理请求和响应的流程。
3.1过滤器分类在Spring Cloud Gateway中,过滤器按照作用范围可以分为两类全局过滤器。对于所有请求,本地筛选器将被阻止,并且仅对指定的路由有效。我们先来了解一下局部滤波器。当我们前面谈到谓词时,我们实际上涉及到了过滤器的使用。在Spring Cloud Gateway中,内置了很多过滤器,如下图所示。
3.2常用过滤器3.2.1 AddRequestParameter为所有匹配的请求添加一个查询参数。以下配置将为所有请求添加一个参数TN=baiduiimageword=beauty。
spring : cloud : gateway : routes :-id : add _ request _ parameter _ route uri : https://image.baidu.com/predicates :-Path=/search/Index/* * filters :-address parameter=TN,Baidu Image-address parameter=Word,Beauty 3.2.2 RequestRateLimiter该过滤器将对所有访问当前网关的请求进行限流过滤。如果是限流的,默认情况下会响应HTTP 429-太多请求。RequestElimitergatewayFilterFactory默认提供RedisRateLimiter的限流实现,使用令牌桶算法实现限流功能。
spring : cloud : gateway : routes :-id : request _ rate limiter _ route uri : https://www.taobao.com/预测:-Path=/TB/* * filters :-strip prefix=1-name : requestratelimiter rgs : redis-rate-limiter . replenishrate 3360 2 redis-rate-limiter . burst capacity : 5k Ey-resolver 3:如果你知道令牌桶,你可以很容易地知道它们的含义。
ReplenishRate:令牌桶中令牌的填充速度,代表每秒允许执行的请求数。BurstCapacity:令牌桶的容量,即令牌桶可以容纳的最大令牌数。指示用户每秒可以执行的最大请求数。Key-resolver:如果关键字标识的电流限制使用redis电流限制,还有一些事情要做:1。用1.pom介绍包。
org . spring framework . boot spring-boot-starter-data-redis-reaction 2。设置redis的地址
Spring : Redis:数据库3360 1密码3360 Eclipse 2019主机3360 LocalHost 3。将以下代码添加到启动类或配置类中
@ BeankeyResolver UserKeyResolver(){//根据请求的ip返回Exchange-Mono限制电流。就(交换。GetRequest()。GetRemoteAddress()。GetAddress()。GetHostAddress());} 3.2.3重试重试网关过滤器工厂是一个请求重试过滤器。当后端服务不可用时,网关将根据配置参数发起重试请求。
spring : cloud : gateway : routes :-id : Retry _ route uri : http://www.example.com预测:-Path=/example/* * Filters :-Name 3360重试参数3360重试次数3360 3状态3360 503-strip prefix=1 retrygateway filter提供了四个参数来控制重试请求。参数描述如下。
重试次数:重试请求的次数,默认值为3。status:HTTP请求返回的状态代码。对指定的状态代码进行重试。例如,在上面的配置中,只有当服务器返回的状态代码是503时,才会启动重试。可在此配置多个状态代码。方法:指定HTTP请求中需要重试的方法类型。默认值是GET。Series:配置错误代码段,这意味着只有满足某个状态代码时才会启动重试。默认值为SERVER_ERROR(5),这意味着5xx段的状态代码将启动重试。如果系列配置了错误代码段,但状态不是,它仍将匹配系列进行重试。3 . 2 . 4 GlobalFilter global filter和GatewayFilter的功能是一样的,只是global filter对所有路由配置都有效。默认情况下,Spring Gateway内置了一些全局过滤器。
GatewayMetricsFilter,提供监视指示器。ReactiveLoadBalanceClient过滤器,集成Ribbon为下游服务实现负载均衡。ForwardRoutingFilter用于本地转发,请求不会转发到下游服务器。NettyRoutingFilter,使用Netty的HttpClient转发HTTP和HTTPS请求.GlobalFiltering链的执行顺序是,当网关收到请求时,过滤Web Handler处理器会将所有全局过滤器实例和所有路由上配置的GatewayFilter实例添加到一个过滤器链中。过滤器链中的所有过滤器都将根据@Order注释指定的数量大小进行排序。
3.2.5自定义过滤器虽然Spring Cloud Gateway提供了很多过滤器,但是在实际应用中,我们难免会涉及到与业务相关的过滤器,比如日志、认证、黑白名单等。云网关提供了过滤器的扩展功能,开发者可以根据实际业务需求定制过滤器,这样我们就可以在网关层实现认证、日志管理、协议转换等功能。同样,自定义过滤器也支持GlobalFilter和GatewayFilter。
3.2.5.1自定义GatewayFilter首先创建一个自定义过滤器类MyDefineGatewayFilterFactory,它继承了AbstractGatewayFilterFactory。
@Componentpublic类MyDefineGatewayFilterFactory扩展AbstractGatewayFilterFactory { Logger Logger=Logger factory . get Logger(MyDefineGatewayFilterFactory . class);公共静态最终字符串NAME _ KEY=’ namepublic MyDefineGatewayFilterFactory(){ super(my config . class);} @ Override public List shortcutfield order(){ return arrays . as List(NAME _ KEY);} @ Override public gateway Filter apply(my config config){ return((exchange,chain)-{ logger . info(‘[Pre]Filter Request,name : ‘ config . getname());//然后接收一个变量,然后之前处理的那个then结束,然后开始处理then接收的这个变量,返回chain.filter (exchange)。then(mono . from runnable()-{ logger . info(‘[post]response filter ‘));}));});}公共静态类MyConfig{私有字符串名称;公共字符串getName(){ return name;} public void set name(String name){ this . name=name;}}}在上述代码中,有几点需要注意:
类名必须始终以GatewayFilterFactory结尾,因为默认情况下,筛选器的名称将采用该自定义类的前缀。name=在这里定义。在应用方法中,包括了过滤前和过滤后。在then方法中,它是执行请求后的后处理。MyConfig是一个只有一个属性名的配置类。这个属性可以用在yml文件中。这个类需要加载到Spring IoC容器中,这里使用@Component注释实现了这个容器。接下来,修改application.yml以添加自定义过滤器配置。
spring : cloud : gateway : routes :-id : define _ route uri 3: http://localhost :8080 predicates :-Path=/define/* * filters :-my define=my _ eclipse 2019此时访问这个过滤器时,会输出下面的日志,表示进入了网关拦截器。
2020-06-02 22:083:21.838信息164-[ioEventLoop-5-2]c . e . s . mydefinegatewayfilterfactory :[Pre]过滤器请求,名称: my _ eclipse 2019 2020-06-02 222:083:21.875信息164 – [ctor-http-nio-5]它不需要额外的配置,只需要实现GlobalFilter接口,所有的路由都会被自动过滤。
@Servicepublic类MyDefineFilter实现GlobalFilter,Ordered { Logger log=Logger factory . get Logger(MyDefineFilter . class);@ Override public Mono filter(server webexchange exchange,GatewayFilterChain chain){ log . info(‘[pre]-Enter MyDefineFilter ‘);返回chain.filter(交换)。然后(mono . from runnable(()-{ log . info(‘[post]-返回结果’);}));} @ Override public int get order(){ return 0;}}getOrder表示这个过滤器的执行顺序。该值越小,执行优先级越高。需要注意的是,我们通过AbstractGatewayFilterFactory实现的本地过滤器不指定顺序,其默认值为0。如果要设置多个过滤器的执行顺序,可以重写getOrder方法。
第四章路由4.1基于集群负载均衡的路由当要路由的目标服务是集群节点时,会涉及到集群路由。Spring Cloud Gateway提供了LoadBalancerClientFilter全局过滤器来实现负载均衡的分析。1.增加jar包依赖性
spring框架。云泉-云启动器-网飞-尤里卡-客户端2 .用户项目也要注册到尤里卡上面去3.修改应用程序。阳明海运股份有限公司配置
春天:应用程序:名称:网关redis :数据库: 1密码:日食2019主机:本地主机云:网关:路由:-id : getUser uri : lb ://user #修改这里谓词s :-Path=/get/* *发现: #修改这里定位器:启用:真小写-服务id :真实服务器:端口: 9527 eureka : #修改这实例:主机名:网关-9527客户端:服务-url:向尤里卡注册:真实获取-注册:真实默认区域: http://127 .0 .0 .3561/尤里卡增加部分的配置说明如下
小写服务id:是否使用服务编号的小写,默认是大写春天。云。网关。发现。定位器。已启用:开启从注册中心动态创建路由的功能100 .上呼吸道感染中配置的lb://表示从注册中心获取服务,后面的用户表示目标服务在注册中心上的服务名重启网关-公共项目,访问:http://localhost/get/3接口。
4.2 动态路由的实现在实际应用中,我们还会存在一种:动态配置路由的需求。也就是在运行过程中,动态增加或者修改网关路由配置,这个需求在春云网关中如何实现呢?在春云网关中,提供了GatewayControllerEndpoint这个类来实现路由的动态修改,可以通过执行机构打开这些端点信息1.添加砰的一声依赖
spring框架。靴子弹簧-靴子-起动机-执行器2 .修改应用程序. yml开发所有端点
管理:端点:网站:公开:包含: *4.2.1检索网关中定义的路由通过这个地址:http://localhost :9527/执行器/网关/路由可以获得当前网关中所有定义的路由
[{谓词: ‘路径:[/get/* *],匹配尾随斜杠’ : true ‘,route_id: ‘getUser ‘,filters: [ ],uri: ‘lb://user ‘,order : 0 0,}]其中:
路线标识表示路由编号路由_对象。谓词表示路由的条件匹配谓词路由_对象。过滤器表示网关过滤器命令路由顺序4.2.2 查找特定的路由信息http://localhost :9527/actuator/网关/routes/{ route _ id }
4.2.3 刷新路由缓存帖子请求} http://本地主机:9527/actuator/网关/刷新
4.2.4 增减、修改路由/gateway/routes/{ id } @邮局映射新增一个路由信息/gateway/routes/{ id } @删除映射删除一个路由信息1.案例演示(添加路由)
通过邮政请求添加一个路由信息,http://localhost :9527/actuator/gateway/routes/Baidu _ route { ‘ uri ‘ : ‘ https://www .百度一下。’ com ‘,’谓词:[{ ‘ args ‘ : { ‘ pattern ‘ : ‘/Baidu/* * ‘ },’ name ‘ 3: ‘ Path ‘ }],’ filters ‘ 3360[{ ‘ args ‘ : { ‘ _ genkey _ 0执行:{POST请求} http://本地主机:9527/actuator/网关/刷新刷新路由。通过访问:http://localhost :9527/执行器/网关/路由查看当前路由列表,可以发现多了一个段这样的内容{谓词:’路径:[/Baidu/* *],匹配尾随斜杠: true ‘,route_id: ‘baidu_route ‘,filters :[‘[[strip prefix parts=1],order=1]’ ],uri : ‘ https://www .百度一下。com :443 ‘,订单:}此时我们访问:http://localhost :9527/百度,就会路由到百度搜索引擎这个网址。2.案例演示(删除路由)
通过/gateway/routes/{ id } @ delete mapping删除路由信息。可以通过postman调用/gateway/routes/Baidu _ route(删除请求)来删除路由。删除路由后,再次访问路由列表页面,可以发现路由信息已经被删除。4.2.5小结基于Spring Cloud Gateway默认方法的动态路由解释完毕,但是动态路由信息的更新是通过这个表单,基于内存实现的。一旦服务重启,所有新增的路由配置信息都会被清除,所以这个时候我们可以参考类GatewayControllerEndpoint自己实现一套动态路由方法。并且路由信息被持久化。在实际开发中,也可以直接添加Nacos作为配置中心。
下面预测网关核心源代码分析
暂无讨论,说说你的看法吧