SpringCloud - GateWay服务网关
创始人
2024-02-19 09:09:08
0

文章目录

  • 一. Gateway概述
    • 1.Gateway是什么
    • 2. Gateway作用
    • 3. 微服务架构中网关的位置
    • 4. SpringCloud Gateway概念
    • 5. SpringCloud Gateway IO 模型
  • 二.Gateway的三大核心概念
    • 1. Route 路由
    • 2. Predicate 断言
    • 3. Filter 过滤
    • 4. 总结
  • 三.Spring Cloud Gateway工作流程
  • 四.服务搭建
    • 1. 创建cloud-gateway-gateway-9527 模块
    • 2. 写pom
    • 3. 改yml
    • 4. 主启动
    • 5. 网关路由映射
    • 6. 测试
  • 五.路由配置的两种方式
    • 1. YML 配置
    • 2. 代码配置
  • 六.Gateway 动态路由
  • 七.Predicate 断言的使用
    • 1. 常用的断言
    • 2.小总结(pom)
  • 八.Filter 过滤器
    • 1. 什么是Filter
    • 2. 自定义过滤器
      • 2.1 实现两个接口
      • 2.2 作用
      • 2.3 演示代码

一. Gateway概述

1.Gateway是什么

gateway 官网:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/

在微服务架构中,一个系统往往由多个微服务组成,而这些服务可能部署在不同机房、不同地区、不同域名下。这种情况下,客户端(例如浏览器、手机、软件工具等)想要直接请求这些服务,就需要知道它们具体的地址信息,例如 IP 地址、端口号等。

这种客户端直接请求服务的方式存在以下问题:

  • 当服务数量众多时,客户端需要维护大量的服务地址,这对于客户端来说,是非常繁琐复杂的。
  • 在某些场景下可能会存在跨域请求的问题。
  • 身份认证的难度大,每个微服务需要独立认证。

2. Gateway作用

API 网关是一个搭建在客户端和微服务之间的服务,我们可以在 API 网关中处理一些非业务功能的逻辑,例如权限验证、监控、缓存、请求路由等。

API 网关就像整个微服务系统的门面一样,是系统对外的唯一入口。有了它,客户端会先将请求发送到 API 网关,然后由 API 网关根据请求的标识信息将请求转发到微服务实例。

对于服务数量众多、复杂度较高、规模比较大的系统来说,使用 API 网关具有以下好处:

  • 客户端通过 API 网关与微服务交互时,客户端只需要知道 API 网关地址即可,而不需要维护大量的服务地址,简化了客户端的开发。
  • 客户端直接与 API 网关通信,能够减少客户端与各个服务的交互次数。
  • 客户端与后端的服务耦合度降低。
  • 节省流量,提高性能,提升用户体验。
  • API 网关还提供了安全、流控、过滤、缓存、计费以及监控等 API 管理功能。

常见的 API 网关实现方案主要有以下 5 种:

  • Spring Cloud Gateway
  • Spring Cloud Netflix Zuul
  • Kong
  • Nginx+Lua
  • Traefik

3. 微服务架构中网关的位置

在这里插入图片描述

4. SpringCloud Gateway概念

SpringCloud Gateway 是在建立在 Spring 生态系统之上的 API 网关服务,基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式,以及提供一些强大的过滤器功能,例如:安全,监控/指标、熔断、限流、重试等。

Spring Cloud Gateway 是基于 WebFlux 框架实现的,而 WebFlux 框架底层则使用了高性能的 Reactor 模式通信框架 Netty。

5. SpringCloud Gateway IO 模型

Zuul 1.x 的 IO 模型:

SpringCloud 中所集成的 Zuul 1.x 版本,采用的是 Tomcat 容器,使用的是传统的 Servlet IO 处理模型。servlet 由 servlet container 进行生命周期管理:

  1. container 启动时构造 servlet 对象并调用 servlet.init() 进行初始化;
  2. container 关闭时调用 servlet.destory() 销毁 servlet;
  3. container 运行时接受请求,并为每个请求分配一个线程(一般从线程池中获取空闲线程)然后调用 service()。

在这里插入图片描述

上述模式的缺点:servlet 是一个简单的网络 IO 模型,当请求进入 servlet container 时,servlet container 就会为其绑定一个线程,在并发不高的场景下这种模型是适用的。但是一旦高并发,线程数量就会上涨,而线程资源代价是昂贵的(上线文切换,内存消耗大)严重影响请求的处理时间。在一些简单的业务场景下,不希望为每个请求分配一个线程,只需要一个或几个线程就能应对极大并发的请求,这种业务场景下 servlet 模型没有优势。

所以 Zuul 1.x 是基于 servlet 阻塞 IO 模型的 API 网关,即 Spring 实现了处理所有 request 请求的一个 servlet(DispatcherServlet),并由该 servlet 阻塞式处理处理。每次 I/О 操作都是从工作线程中选择一个执行,请求线程被阻塞到工作线程完成。所以 Zuul 1.x 无法摆脱 servlet 模型的弊端。

虽然 Zuul 2.0 开始,使用了 Netty 非阻塞和支持长连接,并且已经有了大规模 Zuul 2.0 集群部署的成熟案例,但是,SpringCloud 官方已经没有集成该版本的计划了。

GateWay 非阻塞异步模型

传统的Web框架,比如说:Struts2,SpringMVC 等都是基于 Servlet APl 与 Servlet 容器基础之上运行的。

但是在 Servlet3.1 之后有了异步非阻塞的支持。而 WebFlux 是一个典型非阻塞异步的框架,它的核心是基于 Reactor 的相关 API 实现的。Spring WebFlux 是 Spring 5.0 引入的新的响应式框架,区别于 Spring MVC,它不需要依赖 Servlet APl,它是完全异步非阻塞的,并且基于 Reactor 来实现响应式流规范。

SpringCloud Gateway 是基于 WebFlux 框架实现的,而 WebFlux 框架底层则使用了高性能的 Reactor 模式通信框架 Netty。

二.Gateway的三大核心概念

1. Route 路由

路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由。

2. Predicate 断言

路由转发的判断条件,我们可以通过 Predicate 对 HTTP 请求进行匹配,例如请求方式、请求路径、请求头、参数等,如果请求与断言匹配成功,则将请求转发到相应的服务

3. Filter 过滤

过滤器,我们可以使用它对请求进行拦截和修改,还可以使用它对上文的响应进行再处理。

4. 总结

  • web 请求,通过一些匹配条件,定位到真正的服务节点,并在这个转发过程的前后,进行一些精细化控制
  • predicate 就是我们的匹配条件
  • filter:就可以理解为一个无所不能的拦截器,有了这两个元素,再加上目标的uri,就可以实现一个具体的路由了。

在这里插入图片描述

三.Spring Cloud Gateway工作流程

在这里插入图片描述

Spring Cloud Gateway 工作流程说明如下:

  1. 客户端将请求发送到 Spring Cloud Gateway 上。
  2. Spring Cloud Gateway 通过 Gateway Handler Mapping 找到与请求相匹配的路由,将其发送给 Gateway Web Handler
  3. Gateway Web Handler 通过指定的过滤器链(Filter Chain),将请求转发到实际的服务节点中,执行业务逻辑,返回响应结果返回给客户端。
  4. 过滤器之间用虚线分开是因为过滤器可能会在转发请求之前(pre)或之后(post)执行业务逻辑。
  5. 过滤器(Filter)可以在请求被转发到服务端前,对请求进行拦截和修改,例如参数校验、权限校验、流量监控、日志输出以及协议转换等。
  6. 过滤器可以在响应返回客户端之前,对响应进行拦截和再处理,例如修改响应内容或响应头、日志输出、流量监控等。

总而言之,客户端发送到 Spring Cloud Gateway 的请求需要通过一定的匹配条件,才能定位到真正的服务节点。在将请求转发到服务进行处理的过程前后(pre 和 post),我们还可以对请求和响应进行一些精细化控制。

Predicate 就是路由的匹配条件,而 Filter 就是对请求和响应进行精细化控制的工具。有了这两个元素,再加上目标 URI,就可以实现一个具体的路由了。

核心逻辑:路由转发+执行过滤链

四.服务搭建

1. 创建cloud-gateway-gateway-9527 模块

2. 写pom

做网关不需要添加 web starter


cloud2022com.jm.springcloud1.0-SNAPSHOT4.0.0cloud-gateway-gateway9527org.springframework.cloudspring-cloud-starter-gatewayorg.springframework.cloudspring-cloud-starter-netflix-eureka-clientcom.jm.springcloudcloud-api-commons${project.version}org.springframework.bootspring-boot-devtoolsruntimetrueorg.projectlomboklomboktrueorg.springframework.bootspring-boot-starter-testtest

3. 改yml

server:port: 9527spring:application:name: cloud-gatewayeureka:client:register-with-eureka: truefetch-registry: trueservice-url:defaultZone: http://eureka7001.com:7001/eureka

4. 主启动

package com.jm.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527 {public static void main(String[] args) {SpringApplication.run(GateWayMain9527.class, args);}}

5. 网关路由映射

我们目前不想暴露8001端口,希望在8001外面套一层9527

YML新增网关配置

server:port: 9527spring:application:name: cloud-gatewaycloud:gateway:routes:- id: payment_routh               #路由的ID,没有固定规则,但要求唯一,建议配合服务名称uri: http://localhost:8001      #匹配后提供的服务的路由地址predicates:- Path=/payment/get/**        # 断言,路径匹配相配置的进行路由- id: payment_routh2uri:  http://localhost:8001predicates:- Path=/payment/lb/**
eureka:client:register-with-eureka: truefetch-registry: trueservice-url:defaultZone: http://eureka7001.com:7001/eureka

6. 测试

启动网关前访问:http://localhost:8001/get/payment/31
启动网关后访问:http://localhost:9527/get/payment/31

五.路由配置的两种方式

1. YML 配置

spring:application:name: cloud-gatewaycloud:gateway:  #网关路由配置routes:- id: payment_routh    #路由的ID,没有固定规则但要求唯一,建议与服务名对应uri: http://localhost:8001  #匹配后提供服务的路由地址predicates:- Path=/payment/getPaymentById/**    #断言,路径相匹配的进行路由- Method=GET 	#只能时GET请求时,才能访问- id: payment_routh2   #路由的ID,没有固定规则但要求唯一,建议与服务名对应uri: http://localhost:8001  #匹配后提供服务的路由地址predicates:- Path=/payment/lb/**   #断言,路径相匹配的进行路由

测试地址:http://localhost:9527/payment/get/31

2. 代码配置

当请求路径为 /guonei时,转发到 https://news.baidu.com/guonei

@Configuration
public class GateWayConfig {@Beanpublic RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();routes.route("path_route",r -> r.path("/guonei").uri("https://news.baidu.com/guonei"));return routes.build();}
}

测试:http://localhost:9527/guonei

六.Gateway 动态路由

相当于给网关配置一个负载均衡,因为看上面的配置把8001写死了

默认情况下Gateway会根据注册中心注册的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能

开启动态路由:spring.cloud.gateway.discovery.locator.enabled:true;

在添加uri的时候,开头是 lb://微服务名,lb: 负载均衡协议

spring:application:name: cloud-gatewaycloud:gateway:discovery:locator:enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由routes:- id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001          #匹配后提供服务的路由地址uri: lb://cloud-payment-service     #lb:负载均衡协议predicates:- Path=/payment/get/**            # 断言,路径相匹配的进行路由- id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001          #匹配后提供服务的路由地址uri: lb://cloud-payment-service     #lb:负载均衡协议predicates:- Path=/payment/lb/**             # 断言,路径相匹配的进行路由

测试:

因为开启了8001和8002两个端口,所以网关负载均衡的效果是 8001/8002切换

七.Predicate 断言的使用

Spring Cloud Gateway 通过 Predicate 断言来实现 Route 路由的匹配规则。简单点说,Predicate 是路由转发的判断条件,请求只有满足了 Predicate 的条件,才会被转发到指定的服务上进行处理。

使用 Predicate 断言需要注意以下 3 点:

  • Route 路由与 Predicate 断言的对应关系为“一对多”,一个路由可以包含多个不同断言。
  • 一个请求想要转发到指定的路由上,就必须同时匹配路由上的所有断言。
  • 当一个请求同时满足多个路由的断言条件时,请求只会被首个成功匹配的路由转发。

参考gateway官网的断言的例子:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#the-after-route-predicate-factory

1. 常用的断言

常用的Route Predicate

After Route Predicate

  • - After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
  • 匹配该断言时间之后的 uri请求

Before Route Predicate

  • - After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
    - Before=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]

Between Route Predicate

  • - Between=2020-03-08T10:59:34.102+08:00[Asia/Shanghai] , 2020-03-08T10:59:34.102+08:00[Asia/Shanghai]

Cookie Route Predicate

不带cookies访问

带上cookies访问 - Cookie=username,atguigu #并且Cookie是username=atguigu 才能访问

Cookie Route Predicate 需要两个参数,一个时Cookie name,一个是正则表达式。

路由规则会通过获取对应的Cookie name值和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上就不执行

Header Route Predicate
两个参数:一个是属性名称和一个正则表达式,这个属性值和正则表达式匹配则执行;

Host Route Predicate

  • - Host=**.atguigu.com

Method Route Predicate

  • - Method=GET

Path Route Predicate

== Query Route Predicate==

  • - Query=username, \d+ #要有参数名称并且是正整数才能路由

2.小总结(pom)

server:port: 9527spring:application:name: cloud-gatewaycloud:gateway:discovery:locator:enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由routes:- id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001          #匹配后提供服务的路由地址uri: lb://cloud-payment-service     #lb:负载均衡协议predicates:- Path=/payment/get/**            # 断言,路径相匹配的进行路由- id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名#uri: http://localhost:8001          #匹配后提供服务的路由地址uri: lb://cloud-payment-service     #lb:负载均衡协议#filters:#  - AddRequestParameter=X-Request-Id,1024 #过滤器工厂会在匹配的请求头加上一对请求头,名称为X-Request-Id值为1024predicates:- Path=/payment/lb/**             # 断言,路径相匹配的进行路由#- After=2022-11-26T19:14:10.785+08:00[Asia/Shanghai]#- Before=2022-11-26T19:22:29.119+08:00[Asia/Shanghai]#- Between=2022-11-26T19:14:10.785+08:00[Asia/Shanghai], 2022-11-26T19:22:29.119+08:00[Asia/Shanghai]#- Cookie=username,zzyy#- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式#- Host=**.atguigu.com#- Method=GET#- Query=username, \d+  # 要有参数名username并且值还要是整数才能路由eureka:instance:hostname: cloud-gateway-serviceclient: #服务提供者provider注册进eureka服务列表内service-url:register-with-eureka: truefetch-registry: truedefaultZone: http://eureka7001.com:7001/eureka

八.Filter 过滤器

1. 什么是Filter

路由过滤器可用于修改进入的Http请求和返回的Http响应,路由过滤器只能过滤指定路由进行使用。

Spring Cloud Gateway 内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生

官网:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gatewayfilter-factories

声明周期 :

  • pre 在业务逻辑之前
  • post 在业务逻辑之后

种类:

  • 单一的:GatewayFilter
  • 全局的:GlobalFilter

2. 自定义过滤器

2.1 实现两个接口

implements GlobalFilterOrdered

2.2 作用

全局日志记录
统一网关鉴权

2.3 演示代码

package com.jm.springcloud.filter;import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.util.Date;@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {@Overridepublic Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info("************come in MyLogGateWayFilter: "+new Date());String uname = exchange.getRequest().getQueryParams().getFirst("uname");if(uname==null){log.info("********用户名为null,非法用户,/(ㄒoㄒ)/~~");exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);return exchange.getResponse().setComplete();}return chain.filter(exchange);}@Overridepublic int getOrder() {return 0;}
}

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...