百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

微服务架构之API网关——在微服务项目中的技术框架和用法实践

mhr18 2025-05-28 19:06 7 浏览 0 评论

API网关技术实战

在介绍了API网关的相关理论之后,大家可以了解到API网关的作用和优缺点,接下来将为大家介绍API网关在微服务项目中的技术框架和用法实践。

Zuul网关

其实API网关并不是很难的技术,就算没有框架,我们通过原生的Servlet Filter、HttpClient等远程调用方式也能够实现网关的路由和过滤。所以,API网关的精髓在于它解决问题的思路和方式,但框架可以给我们带来很多便利,提高开发效率。下面先来了解一下Spring Cloud大家族中的一款API网关框架:Zuul。

Zuul是使用最广泛的API网关框架之一,由著名的Netflix公司开发,Spring Cloud在Zuul上添加了更高一层的封装,提供请求路由、过滤等多种功能的灵活配置,下面详细介绍Spring Cloud Netflix Zuul框架的具体用法。

1. 路由

首先,我们可以通过https://start.spring.io来创建项目,并且添加Zuul的依赖,或者直接在要开发的API网关项目中添加SpringCloud的依赖及Zuul的依赖,代码如下。

然后,在Spring Boot的启动类上增加@EnableZuulProxy注解即可,代码如下。

关于网关的初始配置完成,Zuul的Spring Cloud Starter会完成实例化相关Bean的工作,接下来看一下在Zuul中如何做路由。

假设我们现在有一个用户服务,端口是8081,提供一个GET方法的接口,请求地址是/users/{id},如果要查询ID1的用户信息,直接访问这个用户服务的接口,URL应该是
GEThttp://localhost:8081/users/1,如果通过Zuul来做路由,只需在application.yml中进行相应的配置即可,代码如下。

如上述代码所示,这里需要声明我们想要的路由规则,首先在zuul.routes下配置一个users的路由规则,规则是请求的路径符合/users/ **就转发给地址http://localhost:8081。例如,这里Zuul的 端 口 是 9000,给 API网关发送一个请求 , 地 址 是
http://localhost:9000/users/1,这个请求就会被Zuul的路由转发给
http://localhost:8081/uesrs/1。

stripPrefix又是什么意思?stripPrefix的默认值是true,即去掉请求的前缀,如我们的路由规则是/users/ **,Zuul会默认请求路径中的/users是路由的规则,而不是真实需要转发的请求路径。例如,我们请求
http://localhost:9000/users/1,如果stripPrefix是true,实际Zuul请求的地址是http://localhost:8081/1,会自动去掉路径中的/uesrs前缀。所以,如果真实服务路径是/uesrs/ **,通过设置stripPrefix为false,Zuul就会直接使用URL加原始请求路径来进行请求的转发。

当然,我们也可以通过让API网关集成注册中心的方式,直接通过服务ID来做路由,这样就不用关心具体的服务地址和端口,做到自动发现服务。

假设现在已经启动Consul作为注册中心,Consul的服务地址是127.0.0.1:8500,用户服务也已经使用注册中心注册了自己的服务,服务ID是user-service(具体服务的注册与发现在第2章已经详细介绍过,这里不再赘述)。作为Spring Cloud的一员,Spring CloudNetflix Zuul使用注册中心的配置和其他服务没有不同,在API网关中创建一个名称为bootstrap.yml的配置文件,其配置内容如下。

然后,修改application.yml文件中的路由规则如下。

这里只需设置Service ID就可以通过注册中心直接路由到对应的服务地址了。当然,因为这里使用了Consul作为注册中心,所以首先要启动一个Consul的实例,如可以使用Docker指令快速启动一个Consul,指令如下。

最后,只需要引入Consul的依赖即可,在build.gradle文件中添加如下内容。

在ZuulApplication上加入@EnableDiscoveryClient注解开启注册功能,代码如下。

启动项目后,可以访问http://localhost:8500来查看服务是否注册成功,如图5.23所示。

2. 服务治理

有人可能会问,既然集成了注册中心,Zuul可以动态地发现服务,如果这个服务部署了多个实例,那么Zuul是否可以做到负载均衡和服务熔断?

通过查看注解@EnableZuulProxy的源码可以知道,Spring CloudNetflix Zuul本身已经集成了Ribbon和Hystrix两个框架,在第2章和第3章中已经详细介绍过,所以Zuul本身已经拥有了负载均衡和服务熔断的能力。

其中需要注意的是,Zuul的负载均衡只支持Service ID的路由方式,如果使用path+Service ID的路由配置,这里不需要写任何代码,Zuul就可以通过内置的RibbonRoutingFilter来实现负载均衡,默认采用Ribbon的轮询方式。

Service ID需要注册中心的支持,如果当前环境没有集成注册中心是否就不能做负载均衡?Ribbon本身的定位是客户端的负载均衡器,并不一定要集成注册中心,如果我们在Zuul中使用URL方式的路由规则,那么该如何做到负载均衡?

这很简单,只需修改少量配置即可,虚拟一个Service ID,然后指定这个Service ID对应的服务地址即可,配置内容如下。

由上述配置可见,我们禁用注册中心,依然配置Service ID为users-service,然后通过指定users-service的listOfServers属性来声明服务对应的地址,多个节点以“,”分隔,这样就可以在不使用注册中心的情况下在Zuul路由时进行负载均衡。

介绍完负载均衡,下面来说服务熔断,之前说过Spring CloudNetflix Zuul本身集成了Hystrix,那么具体如何使用?在第3章介绍过,Hystrix服务熔断的核心思路是能够指定方法的降级(fallback),然后在服务断路时快速地给予调用者反馈,在使用Zuul建立API网关后,请求都由Zuul进行路由到服务端,那么降级应该设置在哪里?在图5.10中,API网关的断路应该针对服务端,所以为了设置服务的降级,Spring Cloud Netflix Zuul提供了相应的接口FallbackProvider,只需实现它,就能设置针对服务级别的熔断策略,代码如下。

其中,getRoute方法需要返回对应的路由规则中配置的ServiceID,这里断路的对象是用户服务,所以返回users-service,当然不使用注册中心也可以做到服务熔断,具体方式和之前介绍的不使用注册中心的负载均衡配置相同,然后在FallbackResponse方法中返回ClientHttpResponse对象作为降级策略,我们可以自由地设置响应的状态信息以及响应头和响应体等内容。

除了服务熔断和降级,Spring Cloud Netflix Zuul还可以配置线程隔离策略。例如,我们可以将Hystrix默认的线程池的隔离策略修改为使用信号量的隔离策略,配置如下。

3. 过滤器

除了路由和服务治理,API网关还有一个重要的功能,即请求的过滤,这里了解一下Zuul中过滤器的用法。在Zuul中,我们可以通过继承Zuul提供的抽象类ZuulFilter来定义一个新的过滤器,代码如下。

其中,filterType()返回过滤器的类型,目前有pre、route、post、error和static共5种类型的过滤器,意义如下。

(1)pre:在路由之前执行。

(2)route:在路由时执行。

(3)post:在路由后执行。

(4)error:在路由发生异常时执行。

(5)static:请求静态资源时执行。

定义了filterType()就等于定义了过滤器的执行时机,那么如果定义了多个pre过滤器,它们的顺序又是怎样的?filterOrder()就是用来定义相同类型的过滤器的执行顺序的,通常如果过滤器没有顺序要求,就可以直接返回0,整型的值越小,对应的过滤器越先执行。

shouldFilter()很好理解,只有返回true,过滤器才会被执行,所以这里可以定义一些规则,或者使用配置文件来灵活地、可插拔地使用过滤器。

run()方法是过滤器的执行方法,想要过滤器完成的事情都会写在run方法中。例如,我们需要给所有路由的返回都加上一个自定义的消息头,那么可以写一个post类型的filter,然后定义run方法,内容如下。

由于run方法没有注入任何参数,因此我们可以通过Zuul提供的RequestContext来获取请求和响应信息,然后修改响应头,加入需要添加的内容。如果想通过过滤器阻止请求的路由,可以使用pre过滤器,然后在run方法中抛出异常即可,代码如下。

如上述代码所示,当请求的令牌认证失败时,可以抛出一个认证异常,这时请求被中断,不过身份认证通常会使用Spring Security来完成,在5.5.3节会介绍Spring Security的基本用法。

除了能够灵活地自定义过滤器,Spring Cloud Netflix Zuul还提供了一些内置的过滤器,如敏感信息头过滤器。我们可以不写代码,通过简单的配置来过滤请求头中的一些敏感信息。通过源码可以得知Spring Cloud Netflix Zuul默认过滤了头部信息中的3种数据:Cookie、Set-Cookie和Authorization。当请求通过Zuul路由到具体的服务时,头部中一旦存在Cookie、Set-Cookie和Authorization的信息,就会被删掉。我们也可以通过配置文件来修改这些配置,内容如下。

这里需要注意的是,新的配置会替换默认的配置,所以如果只想新增加一些敏感头的过滤 , 就要加上Cookie 、 Set-Cookie 和Authorization,代码如下。

关于Zuul的用法就介绍到这里,详细的教程可以查看Spring Cloud Netflix的官方文档,地址为
https://spring.io/projects/spring-cloud-netflix,或者直接访问Zuul在GitHub上的官网,地址是
https://github.com/Netflix/zuul。

Spring Cloud Gateway

Spring Cloud在Netflix Zuul之后又开发了一款新的API网关框架——Spring Cloud Gateway,它是基于Spring 5.x和Spring Boot 2.x所开发的一款支持非阻塞式的API网关框架(不过Zuul从2.x版本开始支持非阻塞的API)。相比Zuul,Spring Cloud Gateway还支持长连接,所以可以支持WebSockets的使用,旨在提供一种简单而有效的方式来路由到API,并为它们提供横切关注点,如安全性、监控/指标和弹性等。

在Spring的官网上列出了Spring Cloud Gateway的功能特性,具体如下。

(1)基于Spring Framework 5、Project Reactor和Spring Boot2.0构建。

(2)能够根据请求的任何属性匹配上路由。

(3)判断条件(Predicates)和过滤器(Filters)可作用于特定的路由。

(4)集成Hystrix断路器。

(5)集成Spring Cloud Discovery Client。

( 6 ) 易于编写的判断条件( Predicates )和过滤器(Filters)。

(7)请求率限制,即限流。

(8)路径重写。

可以看出,Spring Cloud Gateway比Zuul更加灵活,功能更加强大 , 并 且 对 于 Spring Cloud 更加契合,下面介绍 Spring Cloud Gateway的用法。

首先,可以通过工具或https://start.spring.io创建一个新的Gradle项目,加入Spring Cloud Gateway的依赖,build.gradle文件内容如下。

1.路由

假设有一个用户服务,提供一个查询用户的接口,然后和Zuul的用法类似,我们可以在配置文件中快速地增加路由的配置,修改application.yml内容如下。

在上述代码中,我们可以定义多个路由规则,其中id作为路由的唯一标识,uri是原始服务的地址,predicates请求是否匹配的判断条件,配置的条件是Path,即根据请求的路径来判断是否匹配该路由。

除了Path,Spring Cloud Gateway还提供了更加灵活的判断规则。例如,我们可以使用Cookie来进行路由,代码如下。

如上配置就表示只要请求中带有key为test、value为123的Cookie,该请求就会被匹配到这个路由中,当然,还可以进行条件组合,如以下配置。

上述配置就表示请求必须同时满足路径为/users/ **,并且请求中要有test=123和test2=456两组Cookie才会匹配上该路由。

除了Path和Cookie,Spring Cloud Gateway还提供了多种匹配方式。例如,我们可以根据请求头来匹配路由,配置如下。

上述配置就表示请求头中必须包含X-request-id的信息,并且值必须是users-service,这样的请求才会匹配上该路由。此外,还可以根据HTTP的Method来进行路由,如对所有的GET方法进行匹配,具体如下。

或者可以根据请求的参数来进行路由,配置如下。

上述配置就表示请求的URL参数中必须包含a=123的参数才会匹配上该路由,如//localhost: 8080/users/1?a=123。

除了这些匹配方式,Spring Cloud Gateway还提供了一些特别的路由方式,如按照时间的Before、After和Between。这里以Between为例,我们将请求按照时间段的规则进行路由,配置如下。

上述配置就表示时间在2018年1月1日至2018年12月31日的所有请求都将匹配该路由规则。值得注意的是,由于匹配的是客户端发生请求的时间,时间配置需要配置时区。Between表示请求时间在指定的两个时间之间,同理Before和After分别表示请求时间在指定的时间之前和之后,并且只需指定一个时间即可。

此外,Spring Cloud Gateway还提供了基于Host和RemoteAddr的匹配规则,这里不再一一演示,所有的规则都可以进行组合。

2. 过滤

除了路由,Spring Cloud Gateway还提供了很多强大的内置过滤器,而且每个过滤器可以直接配置到路由中。例如,我们可以通过AddRequestHeader和AddResponseHeader来增加请求或响应的头部信息,以AddResponseHeader为例,配置如下。

在请求API网关后,返回的响应头中就可以得到X-test=1的信息。除 了 添 加 头 部 信 息 , 还 可 以 通 过 RemoveRequestHeader和RemoveResponseHeader 来 删 除 请 求 和 响 应 的 头 部 信 息 ,以RemoveRequestHeader为例,配置如下。

上述配置就可以在请求头中删除key为Set-Cookie的头部信息。除了能够修改请求和响应的头部信息,Spring Cloud Gateway还提供了修改请求参数的过滤器,配置如下。

上述配置就可以在请求的路径上加入我们制定的前缀了。例如,请 求 路 径 是 /users/1 , 那 么 实 际 请 求 会 被 路 由 到
http://localhost:8081/myservice/users/1上。

除了上述内置的过滤器,Spring Cloud Gateway还提供了其他的过滤器。例如,用于管理Session的SaveSession过滤器,用于设置状态的SetStatus过滤器,用于重定向的RedirectTo过滤器,等等。

3. 服务治理

除了这些路由级别的过滤器,Spring Cloud Gateway还提供了一些全局的过滤器,如LoadBalancerClient可以帮助我们完成负载均衡的工作。

当然,需要集成注册中心,首先要添加注册中心的相关依赖,在build.gradle中添加如下dependencies。

然后,增加和配置其他注册中心的服务,如增加bootstrap.yml文件,内容如下。

最后,修改路由uri,配置如下。

这里lb://后面就是服务的应用名称,这样Spring Cloud Gateway就能够通过LoadBalancer Client来完成客户端负载均衡的操作。

除了负载均衡,Spring Cloud Gateway还集成了Hystrix,可以完成服务熔断和降级的处理,首先需要添加Spring Cloud Netflix Hystrix的依赖,在build.gradle中添加如下dependencies。

然后,修改application.yml的路由配置,内容如下。

在上述配置中,增加一个Hystrix的过滤器,然后Spring CloudGateway会创建一个HystrixCommand来完成服务熔断和降级的操作,通过参数(args)的配置,可以指定HystrixCommand的name和fallback的uri,配置降级策略为跳转到/users/fallback的地址,所以还需要添加一个降级的服务,在API网关中添加Controller,代码如下。

我们可以将用户服务关闭,测试一下断路是否生效。当关闭用户服务后,再次通过API网关调用用户接口,那么将返回信息usersservice crashed。

除了基础的负载均衡和服务熔断,Spring Cloud Gateway还提供了 基 于 Redis 的 服 务 限 流 的 功 能 , Spring Cloud Gateway 通 过RequestRateLimiter过滤器来完成限流的工作,由于Spring Cloud Gateway是非阻塞的架构,因此需要集成spring-boot-starter-dataredis-reactive 来 连 接 Redis , 在 build.gradle 中 添 加 如 下dependencies。

接下来就可以配置Redis的连接信息,默认是localhost:6379,内容如下。

然后添加RequestRateLimiter过滤器,配置如下。

这里采用的是令牌桶算法(Token Bucket Algorithm),参数
redis-rate-limiter.replenishRate表示允许用户每秒的最大请求数,即令牌桶每秒的填充数率,如设置是10,表示每秒令牌桶最大只能装满10次请求,但是多余的请求不会丢失,而是等待令牌桶中有空闲的空间后再继续执行,
redis-rate-limiter.burstCapacity也是表示 1s 内 允 许 的 最 大 请 求 数 量 , 但 与 replenishRate 的 区 别 是burstCapacity会直接拒绝多余的请求,如burstCapacity设置的值是20,那么一旦请求超过20,多余的请求将被丢弃,不再执行。

当 然 , 限 流 需 要 指 定 一 个 KeyResolver 才 能 正 常 工 作 ,KeyResolver可以理解为限流的维度,如我们根据请求的路径进行限流,配置一个KeyResolver的Bean,内容如下。

在配置文件中,key-resolver: "#{@pathKeyResolver}"指定了Bean的name,即pathKeyResolver,然后相同路径的请求将被限制流速。

关于Spring Cloud Gateway的用法就介绍到这里,可以到Spring Cloud Gateway的官方网站查看更详细的教程。

本文给大家讲解的内容是API网关技术实战

  1. 下篇文章给大家讲解的是Spring Security
  2. 觉得文章不错的朋友可以转发此文关注小编;
  3. 感谢大家的支持!

相关推荐

Team IDE 集成管理工具

Team·IDE工具简介TeamIDE工具集成SSH、FTP、MySql、Redis、Zookeeper、Kafka、Elasticsearch等管理工具Team·IDE功能模块目录结...

MySQL大数据表处理策略,原来一直都用错了……

场景当我们业务数据库表中的数据越来越多,如果你也和我遇到了以下类似场景,那让我们一起来解决这个问题。数据的插入,查询时长较长后续业务需求的扩展,在表中新增字段,影响较大表中的数据并不是所有的都为有效数...

Java程序员你真的甘心只做增删改查吗

各位志同道合的朋友们大家好,我是一个一直在一线互联网踩坑十余年的编码爱好者,现在将我们的各种经验以及架构实战分享出来,如果大家喜欢,就关注我,一起将技术学深学透,我会每一篇分享结束都会预告下一专题最近...

Java后端开发除了增删改查还有什么?

后端的追求:接口稳定、架构合理、业务逻辑清晰、模块拆分合理、支持高并发等。软件本身归根到底都是由算法+数据结构构成的,进一步细化之后,其实就是通过一系列的增删改查操作,构成算法,对数据结构进行操作,赋...

基于shiro实现session持久化和分布式共享

前言本文写下session持久化和分布式共享基于shiro框架对session的管理机制来实现必要性一直处于登陆状态:你登陆微信不可能三天两头就让你重新登陆吧?而是一直处于登陆状态除非主动退出...

为啥工作那么多年,你还是只会增删改查?

你以为没有这样的感觉,工作中领导和同事都非常认可你的能力,但是你想更进一步,却不被认可。想出去看看,跳槽面试,却也是屡屡碰壁。面试的过程中,面试官问技术方案,明明心里很清楚,或者说印象还行,可就是说不...

Java程序员除了做增删改查还能干嘛?

就以Java后端开发为例,说说不同级别程序员干的事情。1初级开发,大概是有3年Java开发经验。22年底,上海,这批程序员如果学历是本科,薪资一般是8k到2w,当然如果能进好公司或互联网大厂,薪资能...

Java面试题及答案总结(2025版持续更新)

大家好,我是Java面试分享面对Java后端岗位的激烈竞争,掌握系统化的知识体系至关重要。本文整理了覆盖主流技术栈的高频面试题,助你高效备战,内容包含:Java基础、并发编程、Spring生态、数据库...

微服务架构之API网关——在微服务项目中的技术框架和用法实践

API网关技术实战在介绍了API网关的相关理论之后,大家可以了解到API网关的作用和优缺点,接下来将为大家介绍API网关在微服务项目中的技术框架和用法实践。Zuul网关其实API网关并不是很难的技术,...

带小白黑客入门,你也可以跟我们一起成为黑客大牛

小编这几天一直在做关于ssrf的实验,这篇文章可以带纯小白黑客入门。靶机ip地址:192.168.2.138查看靶机运行的redis服务。攻击机为ip192.168.2.112.用客户端redis-c...

Python最常见的170道面试题全解析答案(二)

60.请写一个Python逻辑,计算一个文件中的大写字母数量答:withopen(‘A.txt’)asfs:count=0foriinfs.read():ifi.isupper...

Spring Boot项目集成Redis,原来这么简单!

在现代软件开发的“快车道”上,SpringBoot无疑是许多开发者手中的“神兵利器”。它以其“约定大于配置”的理念,大大简化了Java应用的开发和部署过程,让开发者能够将更多精力聚焦于业务逻辑本身。...

Apache Commons Pool——优化你的java内存

大家好,我是吉森。我会持续分享一些开发技巧、经验和技术,如果你也热爱各种开发技术,欢迎关注我。今天我们继续介绍ApacheCommons工具包,今天的主角是:CommonsPool。简单地说,它是...

码农成长系列-基于WebSocket的后台消息提醒

场景描述当用户对app有某些业务操作时,需要将该操作友好地提醒给,有接收提醒权限的后台管理者。技术场景分析经分析,要实现上述业务,业务拆解后可能需要解决如下业务①.触发提醒待推送数据的监听②.提醒时接...

百度直播消息系统的实践和演进

导读:直播业务的核心功能有两个,一个是实时音视频推拉流,另一个是直播间消息流的收发。本文主要介绍百度直播服务内的消息服务系统的设计实践和演化。一、背景直播间内用户聊天互动,形式上是常见的IM消息流;...

取消回复欢迎 发表评论: