阅读本文前可先参考
SpringCloud-SpringCloud根/父项目,开发准备(二)_MinggeQingchun的博客-CSDN博客
一、API网关
引自百度百科
API网关,软件术语,两个相互独立的局域网之间通过路由器进行通信,中间的路由被称之为网关。
任何一个应用系统如果需要被其他系统调用,就需要暴露API,这些API代表着一个一个的功能点。
如果两个系统中间通信,在系统之间加上一个中介者协助API的调用,这个中介者就是API网关
API网关是一个搭建在客户端和微服务之间的服务,我们可以在API网关中处理一些非业务功能的逻辑,例如权限验证、监控、缓存、请求路由等。
API网关就像整个微服务系统的门面一样,是系统对外的唯一入口。有了它,客户端会先将请求发送到API网关,然后由API网关根据请求的标识信息将请求转发到微服务实例。
对于服务数量众多、复杂度较高、规模比较大的系统来说,使用API网关具有以下好处:
- 客户端通过API网关与微服务交互时,客户端只需要知道API网关地址即可,而不需要维护大量的服务地址,简化了客户端的开发。
- 客户端直接与API网关通信,能够减少客户端与各个服务的交互次数。
- 客户端与后端的服务耦合度降低。
- 节省流量,提高性能,提升用户体验。
- API网关还提供了安全、流控、过滤、缓存、计费以及监控等API管理功能。
常见的API网关实现方案主要有以下5种:
- SpringCloudGateway
- SpringCloudNetflixZuul
- Kong
- NginxLua
- Traefik
二、Gateway
SpringCloudGateway是SpringCloud团队基于Spring5.0、SpringBoot2.0和ProjectReactor等技术开发的高性能API网关组件。
SpringCloudGateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty
SpringCloudGateWay最主要的功能就是路由转发,而在定义转发规则时主要涉及了以下三个核心概念
1、Route(路由)
2、Predicate(断言)
3、Filter(过滤)
核心概念 | 描述 |
---|
Route(路由) | 网关最基本的模块。它由一个ID、一个目标URI、一组断言(Predicate)和一组过滤器(Filter)组成。 |
Predicate(断言) | 路由转发的判断条件,我们可以通过Predicate对HTTP请求进行匹配,例如请求方式、请求路径、请求头、参数等,如果请求与断言匹配成功,则将请求转发到相应的服务。 |
Filter(过滤器) | 过滤器,我们可以使用它对请求进行拦截和修改,还可以使用它对上文的响应进行再处理。 |
注:其中Route和Predicate必须同时声明
SpringCloudGateway工作流程
1、客户端将请求发送到SpringCloudGateway上
2、SpringCloudGateway通过GatewayHandlerMapping找到与请求相匹配的路由,将其发送给GatewayWebHandler。
3、GatewayWebHandler通过指定的过滤器链(FilterChain),将请求转发到实际的服务节点中,执行业务逻辑返回响应结果。
4、过滤器之间用虚线分开是因为过滤器可能会在转发请求之前(pre)或之后(post)执行业务逻辑。
5、过滤器(Filter)可以在请求被转发到服务端前,对请求进行拦截和修改,例如参数校验、权限校验、流量监控、日志输出以及协议转换等。
6、过滤器可以在响应返回客户端之前,对响应进行拦截和再处理,例如修改响应内容或响应头、日志输出、流量监控等。
7、响应原路返回给客户端
三、Gateway应用
1、新建一个springbootModule(springcloud-7-service-eureka-gateway)
2、添加spring-cloud-starter-gateway;spring-cloud-starter-netflix-eureka-client等依赖
注:
在gateway网关服务中不能引入spring-boot-starter-web的依赖,否则会报错
spring-cloud-starter-gateway使用的Netty服务器,而spring-boot-starter-web使用的Tomcat服务器;SpringCloudGateway使用是基于WebFlux和Netty开发的,和传统的Tomcat服务器方式不同
<dependencies><!--spring-cloud-starter-netflix-eureka-client--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!--Springcloudgateway网关依赖特别注意:在gateway网关服务中不能引入spring-boot-starter-web的依赖,否则会报错SpringCloudGateway使用是基于WebFlux和Netty开发的,和传统的Tomcat服务器方式不同--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency></dependencies><!--继承统一的父项目--><parent><groupId>com.company</groupId><artifactId>springcloud-demo</artifactId><version>1.0.0</version></parent><groupId>com.company</groupId><artifactId>springcloud-7-service-eureka-gateway</artifactId><version>1.0.0</version><name>springcloud-7-service-eureka-gateway</name><description>DemoprojectforSpringBoot</description><properties><java.version>1.8</java.version></properties><dependencies><!--spring-cloud-starter-netflix-eureka-client--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!--Springcloudgateway网关依赖特别注意:在gateway网关服务中不能引入spring-boot-starter-web的依赖,否则会报错SpringCloudGateway使用是基于WebFlux和Netty开发的,和传统的Tomcat服务器方式不同--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>3、application.properties配置文件
server.port=81#eureka注册中心首页的Application这一栏spring.application.name=springcloud-7-service-eureka-gateway#每间隔5s,向Eureka服务注册中心发送一次心跳,证明服务是否依然“存活”eureka.instance.lease-renewal-interval-in-seconds=2#告诉服务端,如果10s之内没有发送心跳,就代表故障,将本服务踢出eureka.instance.lease-expiration-duration-in-seconds=10#告诉服务端,服务实例以IP作为链接,不是取机器名eureka.instance.prefer-ip-address=false#注册服务实例ID,,服务ID必须唯一springcloud-7-service-eureka-gatewayeureka.instance.instance-id=${spring.application.name}:${server.port}#注册中心的链接地址http://eureka8761:8761/eureka,http://eureka8762:8762/eureka,http://eureka8763:8763/eurekaeureka.client.service-url.defaultZone=http://localhost:8761/eureka#网关路由配置#开启网关,默认开启spring.cloud.gateway.enabled=true#节点routes是一个List对象,其中routes集合中中又包含多个对象,每个对象有三个属性(一个索引[0]代表一个对象)#路由id,没有固定规则,但唯一spring.cloud.gateway.routes[0].id=login-service-route#匹配后提供服务的路由地址;uri统一资源定位符url统一资源标识符spring.cloud.gateway.routes[0].uri=http://localhost:9001#以下是断言条件,必选全部符合条件;断言是给某一个路由来设定的一种匹配规则默认不能作用在动态路由上#断言,路径匹配,只要Path匹配上了/doLogin就往uri转发并且将路径带上注意:Path中P为大写#也可以全局匹配,如/service/**spring.cloud.gateway.routes[0].predicates[0]=Path=/doLogin#只能是GET请求时,才能访问spring.cloud.gateway.routes[0].predicates[0]=Method=GETapplication.yml写法
server:port:81#eureka注册中心首页的Application这一栏spring:application:name:springcloud-7-service-eureka-gateway#网关路由配置cloud:gateway:#开启网关,默认开启enabled:true#节点routes是一个List对象,其中routes集合中中又包含多个对象,每个对象有三个属性(一个索引[0]代表一个对象)routes:#路由id,没有固定规则,但唯一-id:login-service-route#匹配后提供服务的路由地址;uri统一资源定位符url统一资源标识符uri:http://localhost:9001#以下是断言条件,必选全部符合条件;断言是给某一个路由来设定的一种匹配规则默认不能作用在动态路由上predicates:#断言,路径匹配,只要Path匹配上了/doLogin就往uri转发并且将路径带上注意:Path中P为大写#也可以全局匹配,如/service/**-Path=/doLogin#只能是GET,POST请求时,才能访问-Method=GET,POSTeureka:instance:#每间隔5s,向Eureka服务注册中心发送一次心跳,证明服务是否依然“存活”lease-renewal-interval-in-seconds:2#告诉服务端,如果10s之内没有发送心跳,就代表故障,将本服务踢出lease-expiration-duration-in-seconds:10#告诉服务端,服务实例以IP作为链接,不是取机器名prefer-ip-address:false#注册服务实例ID,,服务ID必须唯一springcloud-7-service-eureka-gatewayinstance-id:${spring.application.name}:${server.port}#注册中心的链接地址http://eureka8761:8761/eureka,http://eureka8762:8762/eureka,http://eureka8763:8763/eurekaclient:service-url:defaultZone:http://localhost:8761/eureka注:
(1)Gateway网关建议使用yml文件格式配置,以properties配置比较繁琐,一般公司项目也建议采取yml格式
(2)不管application.properties还是application.yml写法,都要注意断言predicates处的Path=/doLogin和Method=GET,POST写法,不然报如下错误
***************************APPLICATIONFAILEDTOSTART***************************Description:Bindingtotarget[Bindable@4a6facb0type=java.util.List<org.springframework.cloud.gateway.handler.predicate.PredicateDefinition>,value='provided',annotations=array<Annotation>[@javax.validation.constraints.NotEmpty(message={javax.validation.constraints.NotEmpty.message},groups=[],payload=[]),@javax.validation.Valid()]]failed:Property:spring.cloud.gateway.routes[0].predicates[0].pathValue:/doLoginOrigin:classpathresource[application.yml]:23:21Reason:Theelements[spring.cloud.gateway.routes[0].predicates[0].path,spring.cloud.gateway.routes[0].predicates[1].method]wereleftunbound.Property:spring.cloud.gateway.routes[0].predicates[1].methodValue:GET,POSTOrigin:classpathresource[application.yml]:25:23Reason:Theelements[spring.cloud.gateway.routes[0].predicates[0].path,spring.cloud.gateway.routes[0].predicates[1].method]wereleftunbound.4、在SpringBoot的启动类中,添加@EnableEurekaClient注解开启Eureka客户端功能(Gateway网关也是eureka的客户端)
@EnableEurekaClient//Gateway网关也是eureka的客户端@SpringBootApplicationpublicclassEurekaGateway7Application{publicstaticvoidmain(String[]args){SpringApplication.run(EurekaGateway7Application.class,args);}}5、创建一个服务提供者springcloud-7-service-eureka-gateway-login
依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--spring-cloud-starter-netflix-eureka-client--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency></dependencies>application.properties
server.port=9001#设置应用名称,对应Eureka控制台下DSReplicas的Application(集群部署服务提供者,Application一致,对应多个eureka.instance.instance-id)spring.application.name=springcloud-7-service-eureka-gateway-login#每间隔5s,向Eureka服务注册中心发送一次心跳,证明服务是否依然“存活”eureka.instance.lease-renewal-interval-in-seconds=5#告诉服务端,如果10s之内没有发送心跳,就代表故障,将本服务踢出eureka.instance.lease-expiration-duration-in-seconds=10#告诉服务端,服务实例以IP作为链接,不是取机器名eureka.instance.prefer-ip-address=false#注册服务实例ID,,服务ID必须唯一eureka.instance.instance-id=springcloud-7-service-eureka-gateway-login#注册中心的链接地址http://localhost:8761/eurekaeureka.client.service-url.defaultZone=http://localhost:8761/eurekacontroller测试类
@RestControllerpublicclassLoginController{@GetMapping("/doLogin")publicStringdoLogin(Stringname,Stringpwd){System.out.println(name);System.out.println(pwd);//tokenStringtoken=UUID.randomUUID().toString();returntoken;}}6、分别启动本地eureka,gateway,login-service,输入访问http://localhost:81/doLogin
注:
这里启动Gateway网关模块,会明显的在控制台下方看到输出:
Nettystartedonport(s):81
服务者自己的端口9001访问自然无问题