Spring Cloud系列—Spring Cloud Gateway服务网关的部署与使用指南

Gateway网关

文章目录

  • Gateway网关
      • 1. 网关基本简介
        • 1.1 什么是网关
        • 1.2 为什么需要网关?
      • 2. 快速搭建gateway网关
        • 2.1 创建新模块
        • 2.2 引入依赖
        • 2.3 编写启动类
        • 2.4 配置路由规则
        • 2.5 测试
      • 3. 路由过滤
      • 4. 过滤器
        • 4.1 简介
        • 4.2 网关过滤器
          • 4.2.2 种类
        • 4.3 自定义过滤器
          • 4.3.1 自定义GatewayFilter
          • 4.3.2 自定义GlobalFilter
        • 4.4 跨域问题
          • 4.4.1 什么是跨域问题
          • 4.4.2 解决跨域问题
      • 5. 总结

1. 网关基本简介

1.1 什么是网关

网关,简而言之,是一个系统的单一入口点,它接收所有外部请求,并根据请求的特性(如路径、HTTP方法等)将其转发给内部的各个微服务。

比如说,你想要向一个小区内的一个朋友送信,必须要经过看门大爷的同意,大爷如果认为好人,就会把信带给你要送的人;如果大爷认为你是坏人,就会拦截你。

image-20240514143346013

1.2 为什么需要网关?
  1. 路由:微服务架构通常由多个服务组成,每个服务可能部署在不同的地址和端口上。网关可以根据请求的URL或其他条件,将外部请求路由到正确的服务实例上,从而隐藏了服务实例的具体位置。
  2. 负载均衡:当服务有多个实例时,网关可以根据不同的负载均衡策略(如轮询、随机、最少连接等)将请求分发到不同的实例,确保系统资源的有效利用和服务的稳定性。
  3. 统一鉴权和认证:在微服务架构中,每个服务都可能有自己的安全要求。网关可以作为统一的鉴权和认证点,处理所有服务的安全验证,简化了服务之间的安全通信。
  4. 跨域处理:由于浏览器的同源策略,前端应用在访问不同域名或端口的后端服务时可能会遇到跨域问题。网关可以配置CORS(跨源资源共享)策略,允许前端应用安全地访问后端服务。
  5. 熔断和限流:网关可以集成熔断和限流机制,当后端服务出现问题时,网关可以快速失败,防止级联故障。同时,限流可以控制对后端服务的请求速率,防止服务过载。
  6. 监控和日志:网关是所有外部请求的入口点,可以在这一层收集和记录重要的监控数据和日志信息,帮助开发者和运维人员快速定位问题和性能瓶颈。

2. 快速搭建gateway网关

基本步骤:

  1. 创建新模块
  2. 引入网关依赖
  3. 编写启动类
  4. 配置路由规则
2.1 创建新模块

创建一个新模块gatewawy

image-20240514150510201

2.2 引入依赖
        <!--网关--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!--nacos 服务发现--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--负载均衡--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>
2.3 编写启动类
@SpringBootApplication
public class GatewayApplication {public static void main(String[] args) {SpringApplication.run(GatewayApplication.class, args);}
}
2.4 配置路由规则

gateway模块:

server:port: 8080 
spring:application:name: gateway-service # 服务名称cloud:nacos:server-addr: 192.168.56.101:8848 # Nacos服务注册中心的地址和端口gateway:routes:- id: user # 路由的唯一标识符,自定义,需要保证唯一性uri: lb://user-service # 路由的目标服务地址,lb表示使用负载均衡,user-service是注册中心中的服务名predicates: # 路由断言,用来判断请求是否符合路由规则- Path=/users/**,/addresses/** # 路由断言的路径模式,匹配以/users/或/addresses/开头的请求路径

解析:

  1. default-filters部分定义一个全局过滤器,这些过滤器会对所有通过网关的请求生效。
  2. routes部分,定义了一条路由规则,该规则将所有符合指定路径模式的请求路由到user-service服务。这条规则使用了路径断言Path,匹配所有以/users//addresses/开头的请求。通过使用负载均衡lb://前缀,网关能够根据注册中心中的服务实例信息进行负载均衡。

user-service模块:

server:port: 8084
spring:application:name: user-servicecloud:nacos:server-addr: 192.168.56.101:8848
2.5 测试

测试接口:

@ApiOperation("网关测试接口")
@GetMapping("/gateway-test")
public String testGateway(){return "网关测试成功";
}

nacos:

image-20240514160742494

测试:

image-20240514160300872

3. 路由过滤

在前面的gatewayroutes部分有四个属性可以配置:

  • id:路由的唯一标示
  • predicates:路由断言,其实就是匹配条件
  • filters:路由过滤条件
  • uri:路由目标地址,lb://代表负载均衡,从注册中心获取目标微服务的实例列表,并且负载均衡选择一个访问。

我们在配置文件中写的断言规则只是字符串,这些字符串会被 Predicate Factory(断言工厂) 读取并处理,转变为路由判断的条件。例如 Path=/user/** 是按照路径匹配,这个规则是由org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory 类来处理的,这里重点关注路由断言predicates

名称说明示例
After是某个时间点后的请求- After=2037-01-20T17:42:47.789-07:00[America/Denver]
Before是某个时间点之前的请求- Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]
Between是某两个时间点之前的请求- Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver]
Cookie请求必须包含某些cookie- Cookie=chocolate, ch.p
Header请求必须包含某些header- Header=X-Request-Id, \d+
Host请求必须是访问某个host(域名)- Host=**.somehost.org,**.anotherhost.org
Method请求方式必须是指定方式- Method=GET,POST
Path请求路径必须符合指定规则- Path=/red/{segment},/blue/**
Query请求参数必须包含指定参数- Query=name, Jack或者- Query=name
RemoteAddr请求者的ip必须是指定范围- RemoteAddr=192.168.1.1/24
weight权重处理

4. 过滤器

4.1 简介

过滤器是用于修改进入网关的请求和发出网关的响应的组件。过滤器的作用范围可以是特定的路由,也可以是全局的。过滤器可以用来添加或修改请求头和响应头,修改请求体,进行权限校验,限流,熔断等。

4.2 网关过滤器

单体架构时我们只需要完成一次用户登录、身份校验,就可以在所有业务中获取到用户信息。而微服务拆分后,每个微服务都独立部署,不再共享数据。也就意味着每个微服务都需要做登录校验,这显然不可取。

而登录校验必须在请求转发到微服务之前做,否则就失去了意义。网关的请求转发是Gateway内部代码实现的,要想在请求转发之前做登录校验,就必须了解Gateway内部工作的基本原理。

image-20240514161937208

如图所示:

  1. 客户端请求进入网关后由HandlerMapping对请求做判断,找到与当前请求匹配的路由规则(Route),然后将请求交给WebHandler去处理。
  2. WebHandler则会加载当前路由下需要执行的过滤器链(Filter chain),然后按照顺序逐一执行过滤器(后面称为**Filter**)。
  3. 图中Filter被虚线分为左右两部分,是因为Filter内部的逻辑分为prepost两部分,分别会在请求路由到微服务之前之后被执行。
  4. 只有所有Filterpre逻辑都依次顺序执行通过后,请求才会被路由到微服务。
  5. 微服务返回结果后,再倒序执行Filterpost逻辑。
  6. 最终把响应结果返回。

观察得知:如果我们能够定义一个过滤器,在其中实现登录校验逻辑,并且将过滤器执行顺序定义到NettyRoutingFilter之前,就能解决前面的问题。

4.2.2 种类

网关过滤器链中的过滤器有两种:

  • GatewayFilter:路由过滤器,作用范围比较灵活,可以是任意指定的路由Route.
  • GlobalFilter:全局过滤器,作用范围是所有路由,不可配置。

下面是一些常用的Gateway FilterGlobal Filter

  • AddRequestHeader:添加请求头。
  • AddResponseHeader:添加响应头。
  • RewritePath:重写请求路径。
  • PrefixPath:为请求路径添加前缀。
  • SetPath:设置请求路径。
  • Retry:设置重试逻辑。
  • CircuitBreaker:集成熔断器。
  • RequestRateLimiter:限流过滤器。
  • SecureHeaders:添加安全相关的响应头。
  • TokenRelay:用于将认证信息传递给下游服务。

Gateway中内置了很多的GatewayFilter,详情使用可以参考官方文档:

Spring Cloud Gateway

例如AddRequestHeaderGatewayFilterFacotry,顾明思议,就是添加请求头的过滤器,可以给请求添加一个请求头并传递到下游微服务。

使用的使用只需要在application.yaml中这样配置:

spring:cloud:gateway:routes:- id: test_routeuri: lb://test-servicepredicates:-Path=/test/**filters:- AddRequestHeader=key, value # 逗号之前是请求头的key,逗号之后是value

如果想要让过滤器作用于所有的路由,则可以这样配置:

spring:cloud:gateway:default-filters: # default-filters下的过滤器可以作用于所有路由- AddRequestHeader=key, valueroutes:- id: test_routeuri: lb://test-servicepredicates:-Path=/test/**
4.3 自定义过滤器
4.3.1 自定义GatewayFilter
  1. 编写过滤器工厂GatewayFilterFactory

自定义GatewayFilter不是直接实现GatewayFilter,而是实现AbstractGatewayFilterFactory。最简单的方式是这样的:

@Component
public class PrintAnyGatewayFilterFactory extends AbstractGatewayFilterFactory<Object> {@Overridepublic GatewayFilter apply(Object config) {return new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 获取请求ServerHttpRequest request = exchange.getRequest();// 编写过滤器逻辑System.out.println("过滤器执行了");// 放行return chain.filter(exchange); }};}
}

注意:该类的名称一定要以GatewayFilterFactory为后缀!!!

  1. 配置路由规则
spring:cloud:gateway:default-filters:- PrintAny # 此处直接以自定义的GatewayFilterFactory类名称前缀类声明过滤器

另外,这种过滤器还可以支持动态配置参数,不过实现起来比较复杂,示例:

  1. 编写过滤器工厂GatewayFilterFactory

@Component
public class PrintAnyGatewayFilterFactory // 父类泛型是内部类的Config类型extends AbstractGatewayFilterFactory<PrintAnyGatewayFilterFactory.Config> {@Overridepublic GatewayFilter apply(Config config) {// OrderedGatewayFilter是GatewayFilter的子类,包含两个参数:// - GatewayFilter:过滤器// - int order值:值越小,过滤器执行优先级越高return new OrderedGatewayFilter(new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 获取config值String a = config.getA();String b = config.getB();String c = config.getC();// 编写过滤器逻辑System.out.println("a = " + a);System.out.println("b = " + b);System.out.println("c = " + c);// 放行return chain.filter(exchange);}}, 100);}// 自定义配置属性,成员变量名称很重要,下面会用到@Datastatic class Config{private String a;private String b;private String c;}// 将变量名称依次返回,顺序很重要,将来读取参数时需要按顺序获取@Overridepublic List<String> shortcutFieldOrder() {return List.of("a", "b", "c");}// 返回当前配置类的类型,也就是内部的Config@Overridepublic Class<Config> getConfigClass() {return Config.class;}}
  1. 配置路由规则
spring:cloud:gateway:default-filters:- name: PrintAny # 自定义过滤器的名称args: # 过滤器传递的参数,手动指定参数名,无需按照参数顺序a: 1b: 2c: 3
4.3.2 自定义GlobalFilter

自定义GlobalFilter则简单很多,直接实现GlobalFilter即可,而且也无法设置动态参数:

@Component
public class PrintAnyGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 编写过滤器逻辑System.out.println("未登录,无法访问");// 放行// return chain.filter(exchange);// 拦截ServerHttpResponse response = exchange.getResponse();response.setRawStatusCode(401);return response.setComplete();}@Overridepublic int getOrder() {// 过滤器执行顺序,值越小,优先级越高return 0;}
}
4.4 跨域问题
4.4.1 什么是跨域问题

跨域问题(Cross-Origin Resource Sharing, CORS)是指由于浏览器的同源策略(Same-Origin Policy)限制,一个源(域名、协议和端口)的网页无法向另一个源发送HTTP请求的问题。同源策略是一种安全机制,旨在防止恶意网站访问敏感数据。

同源的定义是:如果两个页面的协议、域名(或IP地址)和端口都相同,则它们具有相同的源。例如,以下两个URL具有相同的源:

  • http://example.com:80/index.html
  • http://example.com:80/page.html

而以下URL与上面的URL不同源:

  • https://example.com:80/index.html (协议不同)
  • http://www.example.com:80/index.html (域名不同)
  • http://example.com:81/index.html (端口不同)

当尝试从不同源的客户端发送请求到服务器时,浏览器会阻止这些请求,除非服务器明确允许跨源请求。这就是所谓的跨域问题。

4.4.2 解决跨域问题

全局CORS配置:在网关的配置文件中,可以定义全局的CORS配置,这些配置会应用到所有的路由上。

spring:application:name: gatewaycloud:nacos:server-addr: 192.168.56.101:8848gateway:globalcors:add-to-simple-url-handler-mapping: true # 因为ajax发起者会通过options请求来向服务器询问是否允许跨域,所以需要设置为true来解决options请求被拦截问题corsConfigurations:'[/**]':allowedOrigins: "http://www.xxx.com" # 允许那些网站跨域访问allowedMethods: # 允许的HTTP方法- GET- POST- PUT- DELETEallowedHeaders: "*" # 允许的请求头allowCredentials: true # 是否允许发送CookiemaxAge: 3600 # 预检请求的缓存时间(秒)

5. 总结

本文深入探讨了Spring Cloud Gateway网关的核心概念及其在微服务架构中的快速部署方法,除此之外着重讲解了Gateway过滤器(Filters)的重要性以及相关使用,包括过滤器的种类、自定义过滤器的实现以及过滤器在解决跨域问题中的作用。

至于具体的应用要根据实际开发要求编写,这里就不过多展示了,希望对大家有所帮助。


参考资料:

Gateway网关 - wenxuehai - 博客园 (cnblogs.com)

gateway Strict-origin-when-cross-origin跨域问题解决 | 少将全栈 (whatled.com)

微服务02

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/12510.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

平衡三进制小数详解与进制转换

标准三进制是“逢三进一&#xff0c;退一还三”的机制&#xff0c;平衡三进制与之类似&#xff0c;但就是偏移了一下变得对称了&#xff0c;平衡三进制与标准三进制可以相互转换&#xff0c;但这样显得有点多余了&#xff0c;所以这里只讲平衡三进制与十进制的转换。 数字系统的…

Flutter 中的 ActionChip 小部件:全面指南

Flutter 中的 ActionChip 小部件&#xff1a;全面指南 在Flutter的Material组件库中&#xff0c;ActionChip是一种用于呈现一组相关操作的组件。它通常用于较少的、需要用户立即进行的操作&#xff0c;如过滤、排序或删除。ActionChip在视觉上与ChoiceChip相似&#xff0c;但使…

MyBatis的核心配置文件---configuration.xml

在MyBatis中&#xff0c;configuration.xml 是MyBatis的核心配置文件&#xff0c;它包含了MyBatis的全局配置信息&#xff0c;如数据源配置、事务管理器配置、别名配置、映射文件配置等。尽管在Spring Boot项目中&#xff0c;MyBatis的配置可以大部分通过属性配置在application…

数据结构与算法-排序算法3-插入排序

目录 1.插入排序&#xff1a; 1.介绍&#xff1a; 2.动态图解 3.举例 4.小结插入排序规则 5.插入排序代码 6.运行时间 代码&#xff1a; 运行结果&#xff1a; 1.插入排序&#xff1a; 1.介绍&#xff1a; 数组中n个元素&#xff0c;把这n个待排序元素看成一个有序序…

Oracle JDK 与 OpenJDK:如何选择及其区别

引言 在选择 Java 开发工具包 (JDK) 时&#xff0c;很多开发者可能会困惑于 Oracle JDK 和 OpenJDK 之间的差异。本文将详细分析这两者的区别&#xff0c;帮助大家做出更明智的选择。 背景 2006 年&#xff0c;SUN 公司宣布 Java 开源&#xff0c;推出了 OpenJDK。2009 年&a…

(Java面试题——基础版)JVM、JRE和JDK的关系

JVM Java Virtual Machine是Java虚拟机 &#xff0c;Java程序需要运行在虚拟机上 &#xff0c;不同的平台有自己的虚拟机 &#xff0c;因此Java语言可以 实现跨平台。JVM 负责将 Java 字节码&#xff08;即编译后的 .class 文件&#xff09;翻译成特定平台上的机器码&#xff0…

直播预告-如何快乐学习亚马逊云科技AWS,玩游戏备考亚马逊云科技云从业者认证?

一边玩一边学习亚马逊云科技云技能&#xff0c;这么好的事尊的假的&#xff1f;本周六&#xff08;5约11日&#xff09;晚20点&#xff0c;亚马逊云科技UG云端夜话Night Talk活动精彩回归&#xff5e; 本次亚马逊云科技UG云端夜话直播是什么&#xff1f; 小李哥这次将在多平台…

分析 vs2019 cpp20 规范的 STL 库模板 function ,源码注释并探讨几个问题

&#xff08;1 探讨一&#xff09;第一个尝试弄清的问题是父类模板与子类模板的模板参数的对应关系&#xff0c;如下图&#xff1a; 我们要弄清的问题是创建 function 对象时&#xff0c;传递的模板参数 _Fty , 传递到其父类 _Func_class 中时 &#xff0c;父类的模板参数 _Ret…

Maven配置集profile

在开发场景中&#xff0c;通常有dev、sit和prod三个环境&#xff0c;分别对应开发、内部测试和生产。 在不同的环境中&#xff0c;因为数据、资源等隔离需要&#xff0c;往往需要不同的配置&#xff0c;这样在部署项目的时候就有着多套配置集灵活选择的需求&#xff08;避免手动…

19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

基础知识要求&#xff1a; Java&#xff1a;方法、while循环、for循环 Python&#xff1a; 方法、while循环、for循环 题目&#xff1a; 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head […

论Java和C++方向选择

目录 1.难度2.就业压力3.岗位选择4.薪资待遇5.选择建议小结 1.难度 Java &#xff0c;C&#xff0c; 测开&#xff0c;整体来说三个方向难度相当。 1.仅从语法角度来看&#xff0c;c 是掌控一切&#xff0c;知识都要懂一点&#xff0c;而java的特点在于省心&#xff0c;都封装…

【C++小语法】引用和内联函数(完结篇)

在使用C语言编程过程中&#xff0c;C语言的要求之严格&#xff0c;编程过程之繁琐&#xff0c;大同小异的重复性工作&#xff0c;令C之父使用C语言编程时也深受其扰&#xff0c;于是乎C兼容C小语法诞生了 一、引用 1.引用概念 在C中&#xff0c;引用&#xff08;Reference&am…

【Android踩坑】 Constant expression required

gradle 8&#xff0c;报错 Constant expression required&#xff1a;意思是case语句后面要跟常量 解决1 单击switch语句&#xff0c;键盘按下altenter&#xff0c;将switch-case语句替换为if-else语句(或者手动修改) 解决2 在gradle.properties中添加 android.nonFinalRes…

【卫星影像三维重建随记】obj模型及其纹理材质文件介绍

obj模型及纹理材质介绍 1.介绍1.1 背景1.2 带有纹理色彩的obj三维模型 2.带有纹理信息obj三维模型文件解析2.1 三维模型数据2.2 obj文件内容2.3mtl文件内容 3 参考 1.介绍 1.1 背景 OBJ格式是一种简单且通用的三维模型文件格式&#xff0c;支持多边形网格和基本的几何体类型&…

leetcode.K站中转(python)

开始准备用dfs深度搜索&#xff0c;发现n100&#xff0c;dfs可能会超时&#xff0c;即使用了剪枝。 class Solution:def findCheapestPrice(self, n: int, flights: List[List[int]], src: int, dst: int, k: int) -> int:length k 2ans float(inf)rec []vis [True]*n…

0514媒体处理面试题

编程&#xff1a;将给定字符串中的数字逆序&#xff0c;比如 abc2319bcj453 逆序后为 abc3549bcj132 思路&#xff1a; &#xff08;1&#xff09;双指针 &#xff08;2&#xff09;栈 #include "stdio.h" #include <iostream> #include <string> #in…

Golang RPC实现-day01

导航 Golang RPC实现一、主体逻辑设计二、服务设计1、监听和接收请求2、处理请求(1)服务结构体定义(2)确认请求方和服务方编解码格式(3)循环读取请求(4)解析请求的内容(5)响应请求 三、读取和发送数据到连接中代码 Golang RPC实现 先来一个最简单的版本&#xff0c;后续更新。…

深入解析Java移位运算符

移位运算符是 Java 中常见的位操作符&#xff0c;主要包括左移&#xff08;<<&#xff09;、带符号右移&#xff08;>>&#xff09;和无符号右移&#xff08;>>>&#xff09;。这些运算符在性能优化、低级编程、数据压缩等领域广泛应用&#xff0c;理解和…

Qt学习笔记1.3.4 QtCore-Qt资源系统

文章目录 资源收集文件(.qrc)外部二进制资源内编译(compiled-in)资源压缩使用应用程序中的资源使用库中的资源 Qt资源系统是一种 独立于平台的机制&#xff0c;用于在应用程序的可执行文件中存储二进制文件。如果您的应用程序总是需要一组特定的文件(图标、翻译文件等)&#x…

QT状态机8-使用恢复策略自动恢复属性

当状态分配的属性不再活动时,可能希望将其恢复到初始值,通过设置全局的恢复策略可以使状态机进入一个状态而不用明确制定属性的值。 QStateMachine machine; machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties);当设置了恢复策略以后,状态机将自动恢复所有…