服务网关工作原理,如何获取用户真实IP?

news2024/12/23 0:31:55

文章目录

  • 一、什么是网关
  • 二、网关工作原理 (★)
  • 三、SpringCloud Gateway
    • 3.1 Gateway 简介
    • 3.2 Gateway 环境搭建
    • 3.3 自定义路由规则 (★)
    • 3.4 局部过滤器
    • 3.5 全局过滤器(案例:获取用户真实IP地址) (★)
  • 补充1:不同类型的客户端如何设置网关
  • 补充2:多个全局多滤器的执行优先级
  • 补充3:局部过滤器和全局过滤器的执行优先级


一、什么是网关

在微服务架构中,⼀个系统会被拆分为很多个微服务。那么作为客户端要如何去调用这么多的微服务呢?如果没有网关的存在,我们只能在客户端记录每个微服务的地址,然后分别去调用。

在这里插入图片描述
这样的架构,会存在着诸多的问题:

  • 客户端多次请求不同的微服务,增加客户端代码或配置编写的复杂性。
  • 认证复杂,每个服务都需要独立认证。
  • 微服务做集群的情况下,客户端并没有负载均衡的功能。

上面的这些问题可以借助 API 网关来解决。

API 网关指系统的统一入口,它封装了应用程序的内部结构,为客户端提供统⼀服务,⼀些与业务本身功能无关的公共逻辑可以在这里实现,如:认证、鉴权、监控、路由转发等等

添加上 API 网关之后,系统的架构图变成了如下所示:
在这里插入图片描述


二、网关工作原理 (★)

网关本身也是个微服务,服务注册中心以后,将注册中心的服务列表拉取到本地缓存,并配置相应的路由规则,如下图所示:
在这里插入图片描述

网关组件提供统一请求入口,可以进行统一逻辑的处理,并提供网络隔离的能力(即请求只能通过网关来访问,不能通过某一个服务的IP地址绕过网关来访问)。

当浏览器发起请求http://192.168.10.115/product-serv/product/1
step1:网关获取到请求地址,默认截取域名后面的部分请求路径 /product-serv/product/1
step2:拿到路径信息和路由规则进行匹配,可以获取到对应的服务名product-service
step3:拿到服务名在本地的缓存列表中找到对应的IP地址列表,基于 Ribbon 实现负载均衡算法得出 IP 地址。
step4:进行 URL 地址拼接 http://192.168.10.110/product/1,最终进行网络的调用。


三、SpringCloud Gateway

3.1 Gateway 简介

  Spring Cloud Gateway 是 Spring 公司基于Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供⼀种简单有效的统⼀的 API 路由管理方式。它的目标是替代 Netflflix Zuul,其不仅提供统⼀的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控和限流。

  Spring Cloud Gateway 存在诸多优点,如:性能强劲、功能强大、易扩展,其内置了很多实用的功能,例如转发、监控、限流等。但也存在缺点,如:不能将其部署在 Tomcat、Jetty 等 Servlet 容器里,只能打成 jar 包执行,需要 Spring Boot 2.0及以上的版本才支持等。


3.2 Gateway 环境搭建

1、创建一个 api-gateway 的模块,导入相关依赖:

<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.axy</groupId>
        <artifactId>shop-parent</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <artifactId>api-gateway</artifactId>
    <name>api-gateway</name>

    <dependencies>
        <!--gateway⽹关-->
        <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>
        ...
    </dependencies>
    <build>
    	<finalName>api-gateway</finalName>
    </build>
</project>

2、编写启动类

@SpringBootApplication
@EnableDiscoveryClient
public class ApiGateWayServer {
    public static void main(String[] args) {
        SpringApplication.run(ApiGateWayServer.class, args);
    }
}

3、编写配置⽂件

server:
  port: 9000
spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          enabled: true # 让gateway可以发现nacos中的微服务

注:spring.cloud.gateway.discovery.locator.enabled=true 的作用是让 Gateway 开启服务注册和发现的功能,并且为每一个微服务创建一个默认的路由,该路由将以服务名开头的请求路径转发到对应的服务。如:/product-service/** 转发到 product-service 的服务下。

4、启动测试
在这里插入图片描述


3.3 自定义路由规则 (★)

gateway 提供了默认的路由规则,但也支持自定义规则,具体属性如下:
① id:路由标识符,区别于其他 Route。
② uri:路由指向的目的地 uri,即客户端请求最终被转发到的微服务
③ order:用于多个 Route 之间的排序,数值越小排序越靠前,匹配优先级越高
④ predicate:断言的作用是进行条件判断,只有断言都返回真,才会真正的执行路由
⑤ filters:过滤器用于修改请求和响应信息

server:
  port: 9000
spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          enabled: true # 让gateway可以发现nacos中的微服务
      routes: # 自定义路由配置
        - id: product_route # 路由名称,保证唯一
          uri: lb://product-service # 将符合条件的请求转发到哪个微服务,lb表示对服务进行负载均衡
          predicates: # 拦截哪些请求
            - Path=/product-serv/**
          filters:  # 前台访问:http://localhots:9000/product-service/product/1 去掉第一层以后路径以后,http://product-service/product/1
            - StripPrefix=1 # 在转发请求之前,将拦截到的第一层路径删除掉
        - id: order_route
          uri: lb://order-service
          predicates:
            - Path=/order-serv/**
          filters:
            - StripPrefix=1

注:StripPrefix=1 表示在请求转发请求之前,将拦截到的第一层路径删除掉。
如:前台访问http://localhots:9000/product-service/product/1 去掉第一层以后路径以后变成 http://product-service/product/1

启动测试:
在这里插入图片描述


3.4 局部过滤器

局部过滤器是针对单个路由(或者单个服务)的过滤器,用以添加针对某一个服务的独立功能。下面以需求的形式讲解一下如何配置局部过滤器。

需求:统计订单服务调用耗时。

编写Filter类,注意名称是有固定格式 xxxGatewayFilterFactory。如下面设置 filters 的属性 Time=true,则编写局部过滤器的类名为 TimeGatewayFilterFactory
在这里插入图片描述
继承 AbstractGatewayFilterFactory<TimeGatewayFilterFactory.Config> 类,其中 Config 类是该类的内部类用于承接配置文件中配置的值,重写 shortcutFieldOrder、apply 两个方法。

/**
 * 局部过滤器
 */
@Component
public class TimeGatewayFilterFactory extends AbstractGatewayFilterFactory<TimeGatewayFilterFactory.Config> {
    public TimeGatewayFilterFactory() {
        super(Config.class);
    }

    // 读取配置⽂件中的参数赋值到配置类 Config 中
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("show");
    }

    // 拦截到之后就会调用 apply 方法,把创建对象时候反射创建出来的 Config 传入进来
    @Override
    public GatewayFilter apply(Config config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                // 前置的逻辑
                if (!config.show) {
                    return chain.filter(exchange);
                }
                System.out.println("前置逻辑");
                long start = System.currentTimeMillis();
                // exchange相当于request
                return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                    long end = System.currentTimeMillis();
                    System.out.println("请求耗时:" + (end - start));
                    // 后置的逻辑
                    System.out.println("后置逻辑");
                }));
            }
        };
    }

    @Setter
    @Getter
    static class Config {
        private boolean show;
    }
}

注:其中 Config 作为内部类,是通过反射将配置文件里面的值设置到对应的属性上。如:配置文件中配置 Time=true,则 show 的值最终为 true。另外, shortcutFieldOrder() 方法的返回值是数组,其用于指定反射时的设置顺序。

如假设:配置文件Time=true,1,hello ,那么 Config 的设置应该有三个值,并且属性名与shortcutFieldOrder() 返回值的数组元素的 “名称” 一一对应,如下:

@Component
public class TimeGatewayFilterFactory extends AbstractGatewayFilterFactory<TimeGatewayFilterFactory.Config> {
    public TimeGatewayFilterFactory() {
        super(Config.class);
    }

    // 读取配置⽂件中的参数赋值到配置类 Config 中
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("show", "xx", "yy");
    }

   ...

    @Setter
    @Getter
    static class Config {
        private boolean show;
        private Long xx;
        private String yy;
    }
}

访问订单服务的时候打印时间如下:
在这里插入图片描述


3.5 全局过滤器(案例:获取用户真实IP地址) (★)

全局过滤器作用于所有路由,无需配置文件配置。通过全局过滤器可以实现对权限的统⼀校验,安全性验证等功能。下面以需求的形式讲解一下如何配置局部过滤器:

需求:实现统⼀鉴权的功能,需要在网关判断请求中是否包含token,如果有则还需要在请求头中设置用户的IP地址,则执行正常逻辑。实现代码如下:

/**
 * 全局过滤器
 */
@Component
public class AuthGlobalFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("全局过滤器前置过滤器");
        // 获取到请求中的token信息,验证token是否有效,如果无效拦截请求
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (StringUtils.isEmpty(token) || !"123".equals(token)) {
            System.out.println("鉴权失败");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        ServerHttpRequest request = exchange.getRequest().mutate().header("REAL_IP", exchange.getRequest().getRemoteAddress().getHostString()).build();

        return chain.filter(exchange.mutate().request(request).build()).then(Mono.fromRunnable(new Runnable() {
            @Override
            public void run() {
                System.out.println("全局过滤器后置过滤器");
            }
        }));
    }
}

这里解释以下,为何要在网关获取用户的地址,因为当请求通过网关转发到微服务后使用 Request.getRomteAddr()获取到的只是网关的地址,因此需要在网关侧获取真实IP。

在这里插入图片描述

另外:鉴权逻辑一般放在拦截器中实现,后面将会详细说明。


补充1:不同类型的客户端如何设置网关

由于不同类型客户端访问微服务时,有些公共逻辑会存在差异,如:第三方访问时有限流的操作等。因此建议针对不同端,设置不同的网关。

在这里插入图片描述


补充2:多个全局多滤器的执行优先级

多个全局多滤器最终都是通过Order值进行排序执行,Order值越小越先执行。

两个全局过滤器Order值相同时,根据文件名字母排序,文件名靠前的优先更高。原因是包扫描时是按照文件的顺序扫描的,然后封装到List集合的,通过Order值排序时如果Order值相同,文件名在前名的依然会排在前面。

但也可以实现Ordered接口,重写 getOrder() 方法,以 Order 进行排序,Order 越小优先级越高。

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
       ...
    }


    @Override
    public int getOrder() {
        return 2;
    }
}

补充3:局部过滤器和全局过滤器的执行优先级

多滤器最终都是通过Order值进行排序执行,Order值越小越先执行。

全局过滤器和局部过滤器Order值相同时,GlobalFilter类型优先更高。

原因是这两种过滤器最终会合并到一个过滤器集合中形成过滤器调用链,源码是通过 list.addAll(); 方法将局部过滤器加到了全局过滤器集合中,addAll()是末尾添加方式,所以 Order 值相同时局部过滤器会排在后面。

参考:https://blog.csdn.net/Anenan/article/details/114691488


文章参考:Java微服务商城高并发秒杀项目实战|Spring Cloud Alibaba真实项目实战+商城双11秒杀+高并发+消息+支付+分布式事物Seata

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

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

相关文章

MapSet之相关概念

系列文章&#xff1a; 1. 先导片--Map&Set之二叉搜索树 2. Map&Set之相关概念 目录 1.搜索 1.1 概念和场景 1.2 模型 2.Map的使用 2.1 关于Map的说明 2.2 关于Map.Entry的说明 2.3 Map的常用方法说明 3.Set的说明 3.1关于Set说明 3.2 常见方法说明 1.搜…

CTFHub技能树-Git泄漏-Index

目录 一、Git索引&#xff08;Index&#xff09;的基本概念 二、解题过程 主旨&#xff1a;使用git泄漏恢复源代码 方法一&#xff1a;使用GitHack手动恢复 方法二&#xff1a;直接使用Git_Extract获取网站源代码拿去flag 当前大量开发人员使用git进行版本控制&#xff0c…

图神经网络(2)预备知识

1. 图的基本概念 对于接触过数据结构和算法的读者来说&#xff0c;图并不是一个陌生的概念。一个图由一些顶点也称为节点和连接这些顶点的边组成。给定一个图G(V,E), 其 中V{V1,V2,…,Vn} 是一个具有 n 个顶点的集合。 1.1邻接矩阵 我们用邻接矩阵A∈Rnn表示顶点之间的连接关…

初识Linux · 有关gdb

目录 前言&#xff1a; 1 预备知识 2 gdb的使用 前言&#xff1a; 当我们Linux学到了这里的时候&#xff0c;我们大概会有一种感觉是&#xff0c;从VS2022转战Linux&#xff0c;写代码对我们来说是一种重新构建读写代码的一个过程&#xff0c;从文本编辑器&#xff0c;到文…

怎样将手机屏幕(远程)投屏到家里的大电视上?

我不住家里&#xff0c;前几次回去都会替老爸老妈清理手机。这两个星期没空回去&#xff0c;老爸吐槽手机用几天就又卡了&#xff0c;其实就是清理一些手机缓存的问题。 我说我远程控制他的手机&#xff0c;给他清理一下。他一听“控制”就不喜欢&#xff0c;说我大了&#xf…

视频中的噪点怎么去除?

在数字视频时代&#xff0c;拍摄高质量的视频成为了许多人的追求。然而&#xff0c;在实际拍摄过程中&#xff0c;由于多种原因&#xff0c;我们常常会遇到视频噪点过多、画面模糊的问题&#xff0c;这不仅影响了观看体验&#xff0c;还可能让精心拍摄的作品大打折扣。那么&…

【生物信息学算法】图算法1:概念和算法

文章目录 1. 图的定义、分类、表达方式图的定义图的分类表达方式Python实现 2.相邻节点和度概念定义python实现 3.路径、距离和搜索路径和距离搜索环 4.图论中的欧拉定理 1. 图的定义、分类、表达方式 图的定义 图G可以由两个集合来定义&#xff0c;即G(V,E)。其中&#xff0…

MapSet之二叉搜索树

系列文章&#xff1a; 1. 先导片--Map&Set之二叉搜索树 2. Map&Set之相关概念 目录 前言 1.二叉搜索树 1.1 定义 1.2 操作-查找 1.3 操作-新增 1.4 操作-删除(难点) 1.5 总体实现代码 1.6 性能分析 前言 TreeMap 和 TreeSet 是 Java 中基于搜索树实现的 M…

申万宏源证券完善金融服务最后一公里闭环,让金融服务“零距离、全天候”

在数字化转型的浪潮中&#xff0c;申万宏源作为金融行业的先锋&#xff0c;持续探索科技如何赋能金融服务&#xff0c;以提升企业效率并优化客户服务体验。面对日益增长的视频化需求&#xff0c;传统的图文形式已难以满足市场与用户的新期待。为了应对这一挑战&#xff0c;申万…

简单梳理一个历史脉络

B 站上王山水老师的一个视频引发的思考&#xff1a;没有司马篡国&#xff0c;能避免300年的大乱世吗&#xff1f; 我的答案如下&#xff1a; 视野放宽到欧亚大陆&#xff0c;广义上公元184年黄巾军起义开启内乱&#xff0c;狭义上公元220年正式进入三国&#xff0c;280年晋统一…

新手做短视频素材在哪里找?做短视频素材工具教程网站有哪些?

本文将为你提供一系列新手友好的视频制作资源&#xff0c;包括素材网站和编辑工具&#xff0c;帮助你快速成为短视频领域的新星。让我们从国内知名的蛙学网开始介绍。 蛙学网&#xff1a;新手的视频素材天堂 对于短视频新手而言&#xff0c;蛙学网绝对是一个宝库。该网站提供了…

1-10 图像增强对比度 opencv树莓派4B 入门系列笔记

目录 一、提前准备 二、代码详解 enhanced_image cv2.convertScaleAbs(image, alpha1.5, beta0) 三、运行现象 四、完整工程贴出 一、提前准备 1、树莓派4B 及 64位系统 2、提前安装opencv库 以及 numpy库 3、保存一张图片 二、代码详解 import cv2 # 增强图像的对比度 …

环境配置!

一 安装CUDA 在安装CUDA之前&#xff0c;建议先看下pytorch的更新版本&#xff0c;应为pytorch更新较慢&#xff0c;请保证CUDA的版本&#xff0c;对应的pytorch版本存在。 去pytorch官网查看电脑支持的cuda版本最高是多少。PyTorch 我这边在网站上看最高支持的CUDA版本为12.…

SpringDataJPA系列(7)Jackson注解在实体中应用

SpringDataJPA系列(7)Jackson注解在实体中应用 常用的Jackson注解 Springboot中默认集成的是Jackson&#xff0c;我们可以在jackson依赖包下看到Jackson有多个注解 一般常用的有下面这些&#xff1a; 一个实体的示例 测试方法如下&#xff1a; 按照上述图片中的序号做个简…

【python】Python中如何通过rembg实现图片背景去除

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

Java预备知识 - day2

1.IDEA的简单使用与介绍 1.1 IDEA的项目工程介绍 Day2_0904&#xff1a;项目名称 E:\0_code\Day2_0904&#xff1a;表示当前项目所在路径 .idea&#xff1a;idea软件自动生成的文件夹&#xff0c;最好不要动 src&#xff1a;srcsourse→源&#xff0c;我们的源代码就放在这…

计算机网络知识点复习——TCP协议的三次握手与四次挥手(连接与释放)

TCP协议的三次握手与四次挥手&#xff08;连接与释放&#xff09; 一、前言二、简单的知识准备1. TCP协议的主要特点2. TCP报文段 三、TCP连接的建立&#xff08;三次握手&#xff09;四、TCP连接的释放&#xff08;四次挥手&#xff09;五、TCP连接与释放的总结六、结束语 一、…

计算机基础知识复习9.6

点对点链路&#xff1a;两个相邻节点通过一个链路相连&#xff0c;没有第三者 应用&#xff1a;PPP协议&#xff0c;常用于广域网 广播式链路&#xff1a;所有主机共享通信介质 应用&#xff1a;早期的总线以太网&#xff0c;无线局域网&#xff0c;常用于局域网 典型拓扑结…

qtdraw-使用qt绘图之开源源码学习

1. 资源介绍 功能&#xff1a;使用qt在画板上绘制各种形状&#xff0c;并保持绘制内容到xml文件中。 项目源码&#xff1a;https://github.com/egan2015/qdraw 软件界面&#xff1a; 1.1 支持shape 6种 1.2 支持的功能 6种&#xff0c;分别是对绘制的图形进行撤销undo&…

计算机网络(四) —— 简单Tcp网络程序

目录 一&#xff0c;服务器初始化 1.0 部分文件代码 1.1 关于Tcp协议 1.2 创建和绑定套接字 1.3 监听 二&#xff0c;服务器启动 2.1 获取连接 2.2 提供服务 2.3 客户端启动源文件 Main.cc 二&#xff0c;客户端编写 2.1 关于Tcp客户端 2.2 客户端代码 2.3 效果…