Gateway网关的实现

news2024/11/22 17:44:58

API网关

  • 网关路由必须支持负载均衡,服务列表是从注册中心拉取的
  • 客户端发出请求的URL指向的是网关,URL还必须要包含目标信息
  • 网关收到URL,通过一定的规则,要能识别出交给哪个实例去处理
  • 网关有能力对请求响应进行修改

引入依赖包

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <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>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
    </dependency>
</dependencies>

配置启动类

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

编写application.yaml的配置文件

server:
  port: 8341
Spring:
  application:
    name: gateway-service
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.200.130:8848
        namespace: ce6fa22e-fc35-4fd3-9568-2cf609059088
        group: JIAGOU_GROUP
        file-extension: yaml
        prefix: ${Spring.application.name}
        heart-beat-interval: 5
    gateway:
      discovery:
        locator:
          enabled: true #启用DiscoveryClient的标志
      routes:
        - id: course-service-route # 路由的唯一标识 http://localhost:8341/course/api/courses/1
          uri: lb://course-agg-service #网关收到请求后将请求转发到 lb://course-agg-service
          predicates:
            - Path=/course/** # 断言匹配请求路径
          filters: # 过滤器,可以做认证、限流、日志等
            - StripPrefix=1 # 针对URL剪切前缀,这里去掉了前缀/course

主要概念

  • routes:路由定义了匹配请求的条件,以及如何将请求转发到下游服务
  • predicates:用于匹配请求的条件,比如请求路径、请求参数、头部信息等。
  • filter:过滤器,进行模式匹配

路由谓词工厂

- After=2017-01-20T17:42:47.789-07:00[America/Denver] # 在某个时间之后
- Before=2017-01-20T17:42:47.789-07:00[America/Denver] #在某个时间之前
 - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver] # 两者之间
 - Cookie=chocolate, ch.p #cookie谓词工厂,此谓词匹配具有给定名称且其值与正则表达式匹配的 Cookie。
 - Header=X-Request-Id, \d+
 - Host=**.somehost.org,**.anotherhost.org
 - Method=GET,POST
  - Path=/red/{segment},/blue/{segment}
  - Query=green
  - RemoteAddr=192.168.1.1/24

Filter工厂

  • AddRequestHeader:向请求添加一个 HTTP 头。
  • AddResponseHeader:向响应添加一个HTTP 头。
  • DedupeResponseHeader:去除响应头中的重复值。
  • PrefixPath:为请求路径添加前缀。
  • PreserveHostHeader:保留原始请求的 Host 头。
  • RedirectTo:重定向请求到另一个 URL。章
  • RemoveRequestHeader:移除请求中的一个 HTTP 头。
  • RemoveResponseHeader:移除响应中的一个HTTP 头。
  • RewritePath:重写请求路径。
  • SetPath:设置请求路径。
  • SetRequestHeader:设置请求头。
  • SetResponseHeader:设置响应头。
  • SetStatus:设置响应状态码。
  • StripPrefix:去除请求路径中的前缀

1网关全局过滤器

@Component
@Order(1)
@Slf4j
public class LoggingGlobalFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        long startTime = System.currentTimeMillis();
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            //Mono.fromRunnable此时所有的请求都处理完成后才执行
            ServerHttpResponse response = exchange.getResponse();
            long endTime = System.currentTimeMillis();
            log.info("请求地址:{},请求方法:{},响应状态码:{},响应时间:{}",request.getURI()
                    ,request.getMethod()
                    ,response.getStatusCode().value(),endTime-startTime);
        }));
    }
}

2实现认证过滤器

在微服务中,服务数量较多,不能再服务中进行认证,会进行统一的认证,认证成功后颁发Token,前端会将令牌放在RequestHeader中

创建一个对所有的请求进行认证的全局过滤器

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class AuthenticationGlobalFilter implements GlobalFilter {

    // 认证头
    private  static final String AUTHENTICATION_HEADER = "Authorization";

    // 登录URL
    private static final String LOGIN_URL = "/api/login";
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if(exchange.getRequest().getPath().toString().contains(LOGIN_URL)){
            return chain.filter(exchange);
        }
        String token = exchange.getRequest().getHeaders().getFirst(AUTHENTICATION_HEADER);
        if(token == null || IsValid(token)){
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            // 请求结束
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    private boolean IsValid(String token) {
        //此处通过工具类校验
        return true;
    }
}

3网关的限流

此处集成了redis

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

自定义一个Config类:但要注意此处的限流策略只能选择一种,也就是说@Bean只能生效一个方法

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;

@Configuration
public class RateLimiterConfiguration {
    /**
     * 使用ip地址作为限流
     * @return
     */
    @Bean
    public KeyResolver ipKeyResolver(){
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
    }

    /**
     * 使用用户id作为限流,需要在请求中携带userId参数
     * @return
     */
    //@Bean
    public KeyResolver userKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
    }

    /**
     * 返回一个KeyResolver对象,用于解析请求的路径
     *
     * @return KeyResolver路径解析器,通过请求对象获取路径值
     */
    //@Bean
    public KeyResolver pathResolver() {
        // Lambda表达式用于创建KeyResolver的实例
        // Mono.just确保返回一个包含请求路径的Mono Flux
        return exchange -> Mono.just(exchange.getRequest().getPath().value());
    }
}

在application.yaml文件中修改策略配置

server:
  port: 8341
Spring:
  application:
    name: gateway-service
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.200.130:8848
        namespace: ce6fa22e-fc35-4fd3-9568-2cf609059088
        group: JIAGOU_GROUP
        file-extension: yaml
        prefix: ${Spring.application.name}
        heart-beat-interval: 5
    gateway:
      discovery:
        locator:
          enabled: true #启用DiscoveryClient的标志
      routes:
        - id: course-service-route # 路由的唯一标识 http://localhost:8341/course/api/courses/1
          uri: lb://course-agg-service #网关收到请求后将请求转发到 lb://course-agg-service
          predicates:
            - Path=/course/** # 断言匹配请求路径
          filters: # 过滤器,可以做认证、限流、日志等
            - StripPrefix=1 # 针对URL剪切前缀,这里去掉了前缀/course
            - name: RequestRateLimiter # 定义限流策略
              args:
                redis-rate-limiter.replenishRate: 1 # 每秒填充的令牌数
                redis-rate-limiter.burstCapacity: 2 # 令牌桶的容量
                key-resolver: "#{@ipKeyResolver}" # 限流key的生成策略
  redis:
    host: 43.143.110.136
    port: 6379
    database: 0
    pool:
      max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
      max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
      max-idle: 8 # 连接池中的最大空闲连接
    password: 1234

当请求数量大于令牌个数时,触发限流策略,状态码显示429
在这里插入图片描述

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

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

相关文章

图论算法(DFS/BFS/拓扑排序/最短路/最小生成树/二分图/基环树/欧拉路径)

DFS 基础 BFS 基础 Leetcode 815. 公交路线 思路&#xff1a; class Solution { public:int numBusesToDestination(vector<vector<int>>& routes, int source, int target) {// 记录经过车站x的公交车编号 hashunordered_map<int, vector<int>> …

frp内网穿透功能使用教程

frp 是一款高性能的反向代理应用&#xff0c;专注于内网穿透。它支持多种协议&#xff0c;包括 TCP、UDP、HTTP、HTTPS 等&#xff0c;并且具备 P2P 通信功能。使用 frp&#xff0c;您可以安全、便捷地将内网服务暴露到公网&#xff0c;通过拥有公网 IP 的节点进行中转。 文档地…

Python3网络爬虫开发实战(15)Scrapy 框架的使用(第一版)

文章目录 一、Scrapy 框架介绍1.1 数据流1.2 项目结构1.3 Scrapy 入门 二、Selector 解析器2.1 XPath 和 CSS 选择器2.2 信息提取2.3 正则提取 三、Spider 的使用3.1 Spider 运行流程3.2 Spider 类分析3.3 Request3.4 Response 四、Download Middleware 的使用4.1 process_requ…

55.【C语言】字符函数和字符串函数(strstr函数)

11.strstr函数 *简单使用 strstr: string string cplusplus的介绍 点我跳转 翻译: 函数 strstr const char * strstr ( const char * str1, const char * str2 ); 或另一个版本char * strstr ( char * str1, const char * str2 ); 寻找子字符串 返回指向第一次出现在字…

PostMan使用变量

环境变量 使用场景 当测试过程中&#xff0c;我们需要对开发环境、测试环境、生产环境进行测试 不同的环境对应着不同的服务器&#xff0c;那么这个时候我们就可以使用环境变量来区分它们 避免切换测试环境后&#xff0c;需要大量的更改接口的url地址 全局变量 使用场景 当…

chapter2-站点首页功能实现

1. 导航功能实现 导航数据的存储&#xff0c;必须要找出导航数据的结构&#xff0c;也就是有哪些属性&#xff1f; 导航位置、导航名称、导航链接、导航序号、是否显示、是否外链、添加时间、更新时间、是否删除 E-R图&#xff0c;如下&#xff1a; 1.1 创建模型 home/model…

Ardupilot开源飞控之VTOL之旅:且败且战

Ardupilot开源飞控之VTOL之旅&#xff1a;且败且战 1. 源由2. 希望3. 打印件3.1 Back_cover_AKK_Race_Ranger_VTX_SMA3.2 CRSF-Ant_mount_TPU3.3 H743_mount 4. 其他问题5. 总结6. 参考资料 1. 源由 折腾了这么久&#xff0c;可是VTOL就是一直没有装起来&#xff0c;主要问题还…

vs2022快捷键异常解决办法

安装了新版本的vs2022&#xff0c;安装成功后&#xff0c;发现快捷键发生异常&#xff0c;之前常用的快捷键要么发生改变&#xff0c;要么无法使用&#xff0c;比如原来注释代码的快捷键是ctrlec&#xff0c;最新安装版本变成了ctrlkc&#xff0c;以前编译代码的快捷键是F6或者…

【delphi】正则判断windows完整合法文件名,包括路径

在 Delphi 中&#xff0c;可以使用正则表达式来检查 Windows 文件名称或路径是否合法。合法的文件名和路径要求符合以下几点&#xff1a; 禁止的字符&#xff1a;文件名和路径不能包含以下字符&#xff1a;<, >, :, ", /, \, |, ?, *。文件名不能以空格或点结束。…

一文讲懂Mac中的环境变量

你是否曾经因为环境变量配置不当而浪费了宝贵的开发时间?你是否好奇为什么有时候在终端输入命令会提示"command not found",而有时候又能正常运行?如果你是一名Mac用户,并且希望真正掌握环境变量的奥秘,那么这篇文章将为你揭开Mac中环境变量的神秘面纱,帮助你成为一…

BFS 解决边权为1的最短路问题

边权为1的最短路问题 最短路问题&#xff1a; 比如说从D->K&#xff0c;找出最短的那条&#xff0c;其中每条路都是有权值&#xff0c;此篇主要讲解的边权为1的最短路问题。 即边权都是一样的。 解法就是从起点开始&#xff0c;做一次BFS&#xff1a; 需要一个队列、一个…

深入理解IP地址分类及子网划分详解

在互联网时代&#xff0c;IP地址是网络通信的基础。无论是访问网站、发送电子邮件&#xff0c;还是进行数据传输&#xff0c;IP地址都扮演着至关重要的角色。本文将详细解析IP地址的分类及子网划分的原理&#xff0c;帮助你更好地理解网络架构及其应用。 一、什么是IP地址 IP…

通信工程学习:什么是TDMA时分多址

TDMA时分多址 TDMA&#xff08;Time Division Multiple Access&#xff0c;时分多址&#xff09;是一种在无线通信中广泛使用的多址接入技术。它通过将时间划分为不重叠的时间帧&#xff0c;并将每个时间帧进一步划分为多个时隙&#xff0c;每个时隙分配给不同的用户或通信系统…

8.JMeter+Ant(基于工具的实现接口自动化,命令行方式)

一、JMeterAnt&#xff08;基于工具的实现接口自动化&#xff09; 如果想要实现自动化&#xff0c;就必须使用命令行。 1.jmeter命令 -n 使用非界面的方式去执行脚本 -t 指定jmeter的脚本位置 -l 生成jtl报告&#xff0c;可以通过查看结果树来解析 -e 生产html格式的报告 -o …

p14 使用阿里云服务器的docker部署NGINX

拉取NGINX的镜像 这里因为之前已经配置过从阿里云的镜像仓库里面拿镜像所以这里直接就执行docker pull nginx拉取NGINX镜像就OK了 运行NGINX镜像 这里执行docker run -d --name nginx01 -p 3344:80 nginx这里3344是服务器访问的端口80是容器内部的端口&#xff0c;可以看到…

Flask-JWT-Extended登录验证, 不用自定义

"""安装:pip install Flask-JWT-Extended创建对象 初始化与app绑定jwt JWTManager(app) # 初始化JWTManager设置 Cookie 的选项:除了设置 cookie 的名称和值之外&#xff0c;你还可以指定其他的选项&#xff0c;例如&#xff1a;过期时间 (max_age)&#xff1…

【贪心】【数据结构-小根堆,差分】力扣2406. 将区间分为最少组数

给你一个二维整数数组 intervals &#xff0c;其中 intervals[i] [lefti, righti] 表示 闭 区间 [lefti, righti] 。 你需要将 intervals 划分为一个或者多个区间 组 &#xff0c;每个区间 只 属于一个组&#xff0c;且同一个组中任意两个区间 不相交 。 请你返回 最少 需要…

vue3 ref的用法及click事件的说明

1、ref可以定义一个简单的属性&#xff0c;也可以是一个复杂的列表、数组等等。 2、为什么要使用 ref&#xff1f;简单的let个变量不行吗&#xff1f;const个变量不行吗&#xff1f; 其实这个跟vue的响应式的系统有关&#xff0c;官方的说明如下&#xff1a; 3、为 ref() 标注…

VMWare中的Centos8:Errors during downloading metadata for repository ‘appstream‘

在VMWare的环境中&#xff0c;安装和部署好Centos8&#xff0c;待设置好网络环境后&#xff0c;安装部署C开发和编译环境&#xff0c;遇到报错&#xff1a; dnf gcc gcc-c -y 解决问题的办法如下, 1. 进入仓库源文件夹&#xff1a;cd /etc/yum.repos.d/ 2. 修改镜像配置{这…

计算机毕业设计 公寓出租系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…