时间:2021-05-02
通过前面几次的分享,我们了解了微服务架构的几个核心设施,通过这些组件我们可以搭建简单的微服务架构系统。比如通过spring cloud eureka搭建高可用的服务注册中心并实现服务的注册和发现;
通过spring cloud ribbon或feign进行负载均衡;通过spring cloud hystrix进行服务容错保护以避免故障蔓延。微服务搭建好了之后我们肯定会提供给外部系统一些统一的restful api服务接口进行调用,
但是当外部系统调用我们的restful api的时候,怎么确定它需要的功能具体是哪个服务提供的呢?这个就涉及到一个路由规则和服务实例列表的维护问题。
这就引入了我们今天的主角--spring cloud zuul,它是基于netflix zuul实现的api网关组件。它可以解决两个大问题:
好,接下来我们就来看下怎么实现这个网关服务。
一、构建网关,配置路由
这里我们还是需要使用到前面的hello-service和feign-consumer服务。我们之前把feign-consumer作为服务消费者,但是别忘了在eureka体系里面,每个服务既是服务提供者又是服务消费者,所以feign-consumer也是一个服务提供者,并且http://localhost:9001/feign-consumer等接口就是它提供的服务。
接下来我们构建一个网关服务,代码结构如下:
代码实现步骤:
新建maven工程api-gateway
修改pom文件
? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <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.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelversion>4.0.0</modelversion> <groupid>com.sam</groupid> <artifactid>api-gateway</artifactid> <version>0.0.1-snapshot</version> <parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-parent</artifactid> <version>1.5.1.release</version> </parent> <properties> <javaversion>1.8</javaversion> </properties> <!-- 使用dependencymanagement进行版本管理 --> <dependencymanagement> <dependencies> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-dependencies</artifactid> <version>camden.sr6</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencymanagement> <dependencies> <!-- 引入zuul依赖 , 它依赖了spring-boot-starter-actuator/spring-boot-starter-hystrix/spring-boot-starter-ribbon--> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-zuul</artifactid> </dependency> </dependencies> </project>新建启动类
? 1 2 3 4 5 6 7 8 9 10 11 12 /** * @enablezuulproxy 开启zuul 的api网关服务功能 * */ @enablezuulproxy @springcloudapplication public class gatewayapp { public static void main(string[] args) { springapplication.run(gatewayapp.class, args); } }新建application.properties
? 1 2 3 4 5 6 7 8 9 10 server.port=5555 spring.application.name=api-gateway #增加路由规则的配置 #通过zuul.routes.<route>.path和zuul.routes.<route>.url进行配置,<route>为路由的名字,可以任意指定,但是一组path和url的路由名要相同 #如下面的例子:所有满足/api-a/** 规则的访问都会被路由转发到//localhost:9001的地址 #也就是说,我们访问http://localhost:5555/api-a/hello的时候,api网关服务就会将该请#求路由到 http://localhost:9001/hello提供的微服务接口上 zuul.routes.api-a.path=/api-a/** zuul.routes.api-a.url=http://localhost:9001 zuul.routes.api-b.path=/api-b/** zuul.routes.api-b.url=http://localhost:9090测试,启动eureka、hello-service、feign-consumer以及本次新加的api-gateway服务,然后访问http://localhost:5555/api-a/feign-consumer
成功访问到了feign-consumer的服务接口--feign-consonsumer。
以上步骤实现了传统路由的配置,这种配置有个大的缺点,就是需要手工在application.properties文件中进行路由规则的配置,当服务很多的时候,维护工作量就会很大。为了减小维护成本,还有另外一种路由--面向服务的路由。
二、面向服务的路由
spring cloud zuul和eureka进行整合,我们可以让路由的path不是映射具体的url,而是具体的某个服务,而服务的url则交给eureka服务发现机制自动维护,这类路由就是面向服务的路由。具体代码配置如下:
修改pom文件,引入eureka依赖
? 1 2 3 4 5 <!-- 引入eureka依赖 --> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-eureka</artifactid> </dependency>修改application.properties配置文件
? 1 2 3 4 5 6 server.port=5555 spring.application.name=api-gateway zuul.routes.api-a.path=/api-a/** #这里用serviceid代替url,用服务名代替ip+端口号 zuul.routes.api-a.serviceid=hello-service eureka.client.service-url.defaultzone=http://localhost:1111/eureka注意:zuul.routes.api-a.url=hello-service也能实现功能,但是它不能进行正常的负载均衡和容错保护。
测试,访问http://localhost:5555/api-a/hello
访问成功。
三、服务路由的默认规则
在面向服务的路由中,由于<route>名字是随意起的,那么是不是可以这样:
? 1 2 zuul.routes.hello-service.path=/hello-service/** zuul.routes.hello-service.serviceid=hello-service<route>名字就是服务名,其实在实际的应用中,我们往往就是这样命名的。如果有这样的规则的话,那zuul就可以帮我们默认实现这样的功能,进一步省去了配置的麻烦。
我们来做个实验,将配置文件改为:
? 1 2 3 server.port=5555 spring.application.name=api-gateway eureka.client.service-url.defaultzone=http://localhost:1111/eureka然后页面访问验证
访问成功。
但是由于默认情况下,eureka上的服务都会被zuul创建默认的映射关系来进行路由,使得我们不想对外开放的服务也被外部访问到,这个时候可以通过配置zuul.ignored-services来进行配置不需要自动创建路由的规则。当zuul.ignored-services=*的时候,所有的服务都不会自动创建路由规则,这个时候需要通过前面的配置进行相关路由配置了。
================华丽的分割线===================
前面说了那么多都是围绕一个问题展开的:路由规则和服务实例的维护问题,那么怎么解决第二个问题(校验冗余问题)呢?
四、请求过滤
为了在api网关中实现对客户端请求的校验,我们可以通过过滤器来实现对请求的拦截和过滤,实现方法比较简单,只需要继承zuulfilter抽象类并实现其四个方法就行了。
修改api-gateway:
新增过滤器类
? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 /** * 继承zuulfilter,并且实现其4个接口 * * 用来进行请求过滤 * */ public class accessfilter extends zuulfilter { logger logger = loggerfactory.getlogger(accessfilter.class); /* * shouldfilter 判断该过滤器是否需要被执行 * * 这里直接返回true,表示该过滤器对所有请求都会生效。 * 实际运用中我们可以利用该函数指定过滤器的有效范围 */ @override public boolean shouldfilter() { return true; } /* * 过滤器的具体逻辑 * * 这里我们通过ctx.setsendzuulresponse(false)让zuul过来请求,不对其进行路由 * 然后通过ctx.setresponsestatuscode(401)设置了返回的错误码 * */ @override public object run() { requestcontext context = requestcontext.getcurrentcontext(); httpservletrequest request = context.getrequest(); object accesstoken = request.getparameter("accesstoken"); logger.info("send {} request to {}", request.getmethod(),request.getrequesturl().tostring()); if(accesstoken == null) { context.setsendzuulresponse(false); context.setresponsestatuscode(401); } return null; } /* filtertype 返回过滤器类型 * 他决定了过滤器在请求的哪个生命周期中执行。这里定义为pre,代表会在请求被路由前执行。 * * pre:请求执行之前filter * route: 处理请求,进行路由 * post: 请求处理完成后执行的filter * error:出现错误时执行的filter */ @override public string filtertype() { return "pre"; } /* * filterorder 返回过滤器的执行顺序 * * 当请求在一个阶段有多个过滤器是,需要根据该方法的返回值来一次执行 * */ @override public int filterorder() { return 0; } }修改启动类
? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 /** * @enablezuulproxy 开启zuul 的api网关服务功能 * */ @enablezuulproxy @springcloudapplication public class gatewayapp { //追加bean的是实现 @bean public accessfilter accessfilter() { return new accessfilter(); } public static void main(string[] args) { springapplication.run(gatewayapp.class, args); } }测试
)访问http://localhost:5555/hello-service/hello,访问失败
)访问http://localhost:5555/hello-service/hello?accesstoken=token,正常访问
修改后的代码结构:
五、拓展延伸
其实路由功能在真正运行时,他的路由映射和请求转发都是由几个不同的过滤器完成的。
路由映射主要通过pre类型的过滤器完成,他将请求路径与配置的路由规则进行匹配,找到需要转发的目标地址。
而请求转发的部分则是由route类型的过滤器完成的,对pre类型过滤器获取的路由地址进行转发。
所以,过滤器可以说是zuul实现api网关功能最为核心的部件,每一个进入zuul的http请求都会经过一系列的过滤器处理链得到请求响应并返回给客户端。
总结
以上所述是小编给大家介绍的spring cloud 使用zuul 实现api网关服务问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!
原文链接:https://www.cnblogs.com/sam-uncle/p/9011400.html
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
SpringCloudGateway服务网关API主流网关有NGINX、ZUUL、SpringCloudGateway、Linkerd等;SpringCloud
zuul各版本实现存在一些微小的变化,总的实现思想未改变,以spring-cloud-netflix-core-1.3.6.RELEASE为例一、zuul的重要
在Spring-Cloud-Gateway之请求处理流程文中我们了解最终网关是将请求交给过滤器链表进行处理,接下来我们阅读Spring-Cloud-Gatewa
SpringCloudZuul是SpringCloud系列的网关实现,具有均衡负载,将非业务性校验剥离出来,使微服务专注于业务的一个组件使用Zuul网关后,所有
在前面我们使用zuul搭建了网关关于网关的作用,这里就不再次赘述了,我们今天的重点是zuul的Filter。通过Filter,我们可以实现安全控制,比如,只有请