springcloud:4.1 GateWay

概述

Gateway

简介

Spring Cloud Gateway基于Spring 5.0、SpringBoot 2.0和Project Reactor等技术开发
旨在为微服务架构提供一种简单有效的、统一的API路由管理方式,并为微服务架构提供安全、监控、指标和弹性等功能
其目标是替代Zuul

特点

易于编写谓词和过滤器,其Predicates和Filters可作用于特定路由
支持路径重写
支持动态路由
集成了Spring Cloud DiscoveryClient

底层原理

简介

Spring Cloud Gateway 用"Netty + Webflux"实现,不要加入Web依赖,否则会报错,它需要加入Webflux依赖

Netty

Netty 是一个基于NIO的客户、服务器端的编程框架。
提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序

WebFlux

1.Webflux模式替换了旧的Servlet线程模型。用少量的线程处理request和response io操作,这些线程称为Loop线程,
而业务交给响应式编程框架处理,响应式编程是非常灵活的,用户可以将业务中阻塞的操作提交到响应式框架的work线程中执行,
而不阻塞的操作依然可以在Loop线程中进行处理,大大提高了Loop线程的利用率
2.Webflux虽然可以兼容多个底层的通信框架,但是一般情况下,底层使用的还是Netty,毕竟,Netty是目前业界认可的最高性能的通信框架。
而Webflux的Loop线程,正好就是著名的Reactor模式IO处理模型的Reactor线程,如果使用的是高性能的通信框架Netty

三大核心概念

路由

路由是 Gateway 的⼀个基本单元
这是网关的基本构建块,它由一个ID,一个目标URI,一组断言和一组过滤器定义,如果断言为真,则路由匹配

断言

也称谓词,实际上是路由的判断规则,一个路由中可以添加多个谓词的组合

输入类型是一个ServerWebExchange。我们可以使用它来匹配来自HTTP请求的任何内容,例如headers或参数

过滤

可以在请求被路由前或者之后对请求进行修改

Gateway 组件使用了⼀种 FilterChain的模式对请求进行处理,每⼀个服务请求(Request)在发送到目标标服务之前都要被⼀串FilterChain处理。

同理,在 Gateway接收服务响应的过程中也会被 FilterChain 处理⼀把

搭建【cloud-gateway9527】

依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

application.yml

server:
  port: 9527
spring:
  application:
    name: cloud-gateway9527
  cloud:
    gateway:
      discovery:
        locator:
          enabled: false    #不开启服务注册和发现的功能
          lower-case-service-id: true #请求路径上的服务名称转换为小写
      #路由配置
      routes:
        #cloud-eureka-pro接口路由
        - id: cloud-eureka-pro
          uri: lb://cloud-eureka-pro
          predicates:
            - Path=/eureka/pro/**
      #跨域配置
      globalcors:
        # 解决options请求被拦截问题
        add-to-simple-url-handler-mapping: true
        cors-configurations:
          # 拦截的请求
          '[/**]':
            # 允许跨域的请求
            #allowedOrigins: "*" # spring boot2.4以前的配置
            allowedOriginPatterns: "*" # spring boot2.4以后的配置
            # 允许请求中携带的头信息
            allowedHeaders: "*"
            # 运行跨域的请求方式
            allowedMethods: "*"
            # 是否允许携带cookie
            allowCredentials: true
            # 跨域检测的有效期,单位s
            maxAge: 36000
logging:
  pattern:
    console: '%d{MM/dd HH:mm:ss.SSS} %clr(%-5level) ---  [%-15thread] %cyan(%-50logger{50}):%msg%n'

启动类

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@Slf4j
@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
        log.info("********** Gateway网关 服务启动成功 *********");
    }
}

相关接口

1.搭建eureka客户端【test-provider8001】

http://t.csdnimg.cn/kIloZ

2.测试网关:http://localhost:9527/payment/index

路由

配置路由

配置文件

spring:
  cloud:
    #路由配置
    routes:
      #cloud-eureka-pro接口路由
      - id: cloud-eureka-pro
        uri: lb://cloud-eureka-pro
        predicates:
          - Path=/eureka/pro/**

配置类

/**
 * JAVA API构建路由规则
 */
@Configuration
public class GatewayConfig {
    @Bean//http://localhost:9527/guonei
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
        //设置路由 路由ID(随意取,不重复即可)|路径匹配规则|跳转的路径
        routes.route("path_rote",r -> r.path("/guonei").uri("https://www.baidu.com/guonei")).build();
        return routes.build();
    }

}

uri的写法

直接写法

- id: route_example
uri: http://example.com
predicates:
- Path=/api/example/**

表示将 `/api/example/**` 的请求路由到 `http://example.com`

转发片段写法

- id: route_example
uri: forward:/internal-service
predicates:
- Path=/api/example/**
表示将/api/example/**的请求转发到网关内部的/internal-service服务  

重定向写法

- id: route_example
uri: redirect:http://new-url.com
predicates:
- Path=/old-url/**
表示将/old-url/**的请求重定向到http://new-url.com

使用 lb:// 前缀实现负载均衡

- id: route_example
uri: lb://service-name
predicates:
- Path=/api/example/**
表示将 /api/example/**的请求通过负载均衡策略转发到名为service-name的服务实例  

使用 DiscoveryClient 做动态路由

- id: route_example
uri: lb://service-name
predicates:
- Path=/api/example/**
filters:
- RewritePath=/api/example/(?<path>.*), /$\{path}
表示将 `/api/example/**` 的请求通过DiscoveryClient进行动态路由,并使用RewritePath过滤器进行路径重写  

动态路由

简介

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

添加Eureka依赖并修改配置文件

我们需要把网关注册到eureka上,然后才能找到注册中心的服务列表

实现思路

搭建两个生产者,但是他们的服务名是一致的,正在配置网关的时候uri写服务名,此时会轮询去调用这两个生产者服务

配置文件示例

#cloud-eureka-pro/cloud-eureka-pro81【动态路由-测试负载均衡】
- id: cloud-eureka-pro-dotailuyou
  uri: lb://cloud-eureka-pro
  predicates:
    - Path=/eureka/pro/port
          

断言

时间方面

注意

需要用UTC时间格式的时间参数

UTC时间格式的时间参数时间生成方法

 public static void main(String[] args) {
        ZonedDateTime now = ZonedDateTime.now();
        System.out.println(now);
    }

After

在该日期时间之后发生的请求都将被匹配

predicates:
  - Path=/payment/**
  - After=2030-02-15T14:54:23.317+08:00[Asia/Shanghai]

Before

在该日期时间之前发生的请求都将被匹配

predicates:
  - Path=/payment/**
  - Before=2030-02-15T14:54:23.317+08:00[Asia/Shanghai]

Between

在datetime1和datetime2之间的请求将被匹配

predicates:
  - Path=/payment/**
  - Between=2030-02-15T14:54:23.317+08:00[Asia/Shanghai],2030-02-15T14:54:23.317+08:00[Asia/Shanghai]
        

请求方面

域名

根据域名断言,是这个域名则通过,不是则不匹配
Host文件新增配置
127.0.0.1 itbaizhan

predicates:
- Path=/payment/**
- Host=itbaizhan

请求方法

这个断言是专门验证HTTP Method的
predicates:
- Path=/payment/**
- Method=GET

请求参数

会从ServerHttpRequest中的Parameters列表中查询指定的属性
predicates:
- Path=/payment/**
- Query=username,\d+

Cookie

顾名思义,Cookie验证的是Cookie中保存的信息,Cookie断言和上面介绍的两种断言使用方式大同小异,
唯一的不同是它必须连同属性值一同验证,不能单独只验证属性是否存在

predicates:
- Path=/payment/**
- Cookie=username,zzyy   

请求头

这个断言会检查Header中是否包含了响应的属性,通常可以用来验证请求是否携带了访问令牌
predicates:
- Path=/payment/**
#请求头要有X-Request-Id属性并且值为整数的正则表达式
- Header=X-Request-Id, \d+

网关过滤器

网关过滤器【内置】

简介

应用在单个路由或者一个分组的路由上

示例:SetStatus过滤器

filters:
    - SetStatus=250 # 修改原始响应的状态码            

内置的网关过滤器

AddRequestHeader    为原始请求添加Header  Header的名称及值
AddRequestParameter    为原始请求添加请求参数    参数名称及值
AddResponseHeader  为原始响应添加Header  Header的名称及值
DedupeResponseHeader   剔除响应头中重复的值 需要去重的Header名称及去重策略
Hystrix    为路由引入Hystrix的断路器保护 HystrixCommand的名称
FallbackHeaders    为fallbackUri的请求头中添加具体的异常信息 Header的名称
PrefixPath 为原始请求路径添加前缀    前缀路径
PreserveHostHeader 为请求添加一个preserveHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host   无
RequestRateLimiter 用于对请求限流,限流算法为令牌桶   keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus
RedirectTo 将原始请求重定向到指定的URL    http状态码及重定向的url
RemoveHopByHopHeadersFilter    为原始请求删除IETF组织规定的一系列Header  默认就会启用,可以通过配置指定仅删除哪些Header
RemoveRequestHeader    为原始请求删除某个Header    Header名称
RemoveResponseHeader   为原始响应删除某个Header    Header名称
RewritePath    重写原始的请求路径  原始路径正则表达式以及重写后路径的正则表达式
RewriteResponseHeader  重写原始响应中的某个Header   Header名称,值的正则表达式,重写后的值
SaveSession    在转发请求之前,强制执行WebSession::save操作 无
secureHeaders  为原始响应添加一系列起安全作用的响应头    无,支持修改这些安全响应头的值
SetPath    修改原始的请求路径  修改后的路径
SetResponseHeader  修改原始响应中某个Header的值  Header名称,修改后的值
SetStatus  修改原始响应的状态码 HTTP 状态码,可以是数字,也可以是字符串
StripPrefix    用于截断原始请求的路径    使用数字表示要截断的路径的数量
Retry  针对不同的响应进行重试    retries、statuses、methods、series
RequestSize    设置允许接收最大请求包的大小。如果请求包大小超过设置的值,则返回 413 Payload Too Large 请求包大小,单位为字节,默认值为5M
ModifyRequestBody  在转发请求之前修改原始请求体内容   修改后的请求体内容
ModifyResponseBody 修改原始响应体的内容 修改后的响应体内容
Default    为所有路由添加过滤器 过滤器工厂名称及值

网关过滤器【自定义】

需求

通过过滤器,配置是否在控制台输出日志信息,以及是否记录日

实现步骤

1.类名必须叫做XxxGatewayFilterFactory,注入到Spring容器后使用时的名称就叫做Xxx。
2.创建一个静态内部类Config, 里面的属性为配置文件中配置的参数, - 过滤器名称=参数1,参数2…
3.类必须继承 AbstractGatewayFilterFactory,让父类帮实现配置参数的处理。
4.重写shortcutFieldOrder()方法,返回List参数列表为Config中属性集合
5.无参构造方法中super(Config.class)
6.编写过滤逻辑 public GatewayFilter apply(Config config)

自定义局部过滤器

@Component
public class LogGatewayFilterFactory extends AbstractGatewayFilterFactory<LogGatewayFilterFactory.Config> {
    public LogGatewayFilterFactory(){
        super(Config.class);
    }
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("consoleLog");
    }
    @Override
    public GatewayFilter apply(Config config) {
        return ((exchange, chain) -> {
            if (config.consoleLog) {
                System.out.println("console日志已开启...");
            }
            return chain.filter(exchange);
        });
    }
    //过滤器使用的配置内容,如 - Log=true中的true会传到这里
    @Data
    public static class Config{private boolean consoleLog;}
}

配置使用

filters:
    # 控制日志是否开启
    - Log=true
          

全局过滤器

全局过滤器【内置】

简介

应用在所有的路由上

内置的全局过滤器

路由过滤器(Forward)
路由过滤器(LoadBalancerClient)
Netty路由过滤器
Netty写响应过滤器(Netty Write Response F)
RouteToRequestUrl 过滤器
路由过滤器 (Websocket Routing Filter)
网关指标过滤器(Gateway Metrics Filter)
组合式全局过滤器和网关过滤器排序(Combined Global Filter and GatewayFilter Ordering)
路由(Marking An Exchange As Routed)

全局过滤器【自定义】

需求

对于验证用户是否已经登录及鉴权的过程,可以在网关统一校验
自定义一个GlobalFIlter,去校验所有请求的请求参数中是否包含“token”,如果不包含请求参数“token”则不转发路由,否则执行正常逻辑

自定义全局过滤器

package com.itbaizhan.filter;

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.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;


/**
 * 自定义全局过滤器,需要实现GlobalFilter和Ordered接口
 */
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (StringUtils.isEmpty(token)) {
            System.out.println("鉴权失败。确少token参数。");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }


        if (!"jack".equals(token)) {
            System.out.println("token无效...");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }


        // 继续执行filter链
        return chain.filter(exchange);
    }


    /**
     * 顺序,数值越小,优先级越高
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}
          

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

1.2 课程架构介绍:STM32H5 芯片生命周期管理与安全调试

1.2 课程架构介绍&#xff1a;STM32H5 芯片生命周期管理与安全调试 下面开始学习课程的第二节&#xff0c;简单介绍下STM32H5芯片的生命周期和安全调试&#xff0c;具体课程大家可以观看STM32官方录制的课程&#xff0c;链接&#xff1a;1.2. 课程架构介绍&#xff1a;STM32H5…

免费阅读篇 | 芒果YOLOv8改进109:注意力机制SimAM:用于卷积神经网络的简单、无参数注意力模块

免费阅读篇|芒果YOLOv8改进109&#xff1a;注意力机制篇SimAM&#xff1a;用于卷积神经网络的简单、无参数注意力模块 &#x1f4a1;&#x1f680;&#x1f680;&#x1f680;本博客 改进源代码改进 适用于 YOLOv8 按步骤操作运行改进后的代码即可 该专栏完整目录链接&#x…

【AIGC调研系列】通义灵码与copilot的对比

通义灵码与GitHub Copilot的对比主要集中在几个方面&#xff1a;代码编写能力、免费性、操作界面和适配性。 首先&#xff0c;在代码编写能力上&#xff0c;虽然GitHub Copilot在整体上要强于通义灵码&#xff0c;但通义灵码的能力也不算弱&#xff0c;并且在某些特定的小类任…

外卖平台订餐流程架构的实践

当我们想要在外卖平台上订餐时&#xff0c;背后其实涉及到复杂的技术架构和流程设计。本文将就外卖平台订餐流程的架构进行介绍&#xff0c;并探讨其中涉及的关键技术和流程。 ## 第一步&#xff1a;用户端体验 用户通过手机应用或网页访问外卖平台&#xff0c;浏览菜单、选择…

服务器遭遇挖矿病毒syst3md及其伪装者rcu-sched:原因、症状与解决方案

01 什么是挖矿病毒 挖矿病毒通常是恶意软件的一种&#xff0c;它会在受感染的系统上无授权地挖掘加密货币。关于"syst3md"&#xff0c;是一种特定的挖矿病毒&#xff0c;它通过在受感染的Linux系统中执行一系列复杂操作来达到其目的。这些操作包括使用curl从网络下载…

stm32-定时器输出比较PWM

目录 一、输出比较简介 二、PWM简介 三、输出比较模式实现 1.输出比较框图(以通用定时器为例) 2.PWM基本结构 四、固件库实现 1.程序1&#xff1a;PWM呼吸灯 2.程序2&#xff1a;PWM驱动直流电机 3.程序3&#xff1a;控制舵机 一、输出比较简介 死区生成和互补输出一般…

计算机网络——物理层(奈氏准则和香农定理)

计算机网络——物理层&#xff08;奈氏准则和香农定理&#xff09; 失真码间串扰奈氏准则&#xff08;奈奎斯特定理&#xff09;极限数据率 噪声信噪比香农定理奈氏准则和香农定理的区别 前面我们已经了解一些数据通信的基本知识&#xff0c;没有看过上一篇得小伙伴可以点击这里…

2024最新小狐狸AI 免授权源码

后台安装步骤&#xff1a; 1、在宝塔新建个站点&#xff0c;php版本使用7.2 、 7.3 或 7.4&#xff0c;把压缩包上传到站点根目录&#xff0c;运行目录设置为/public 2、导入数据库文件&#xff0c;数据库文件是 /db.sql 3、修改数据库连接配置&#xff0c;配置文件是/.env 4、…

每日一题——LeetCode1684.统计一致字符串的数目

方法一 Set()双层for循环遍历 将allowd放入Set集合中&#xff0c;遍历words每一项的每一个字符看是否有allowd不含有的字符 var countConsistentStrings function(allowed, words) {let set new Set(allowed),count0for(let word of words){for(let char of word){if(!set.…

redis 入门01

1.安装与配置 在官网下压缩包并传送给自己的虚拟机或者使用wget直接下载都可以 注意:redis是运行在linux下的基于内存的kv键值对数据库 安装与配置参考 2.经典Hello World 注意设置redis在后台运行,默认是前台进行的 我们配置完成之后首先启动服务器 redis-server 配置文件 这里…

从混沌到秩序——90年代中国数据库的激烈角逐

引言 在数字化浪潮的推动下&#xff0c;数据库技术已成为支撑数字经济的坚实基石。腾讯云TVP《技术指针》联合《明说三人行》特别策划的直播系列——【中国数据库前世今生】&#xff0c;我们将通过五期直播&#xff0c;带您穿越五个十年&#xff0c;深入探讨每个时代的数据库演…

uniapp 跳转返回携带参数(超好用)

天梦星服务平台 (tmxkj.top)https://tmxkj.top/#/ 1.返回界面 uni.$emit(enterPeople, this.entryList)uni.navigateBack({delta: 1}) 2.返回到的界面&#xff08;接收数据界面&#xff09; onShow() {let that thisuni.$on(enterPeople,function(enterPeopledata){console.…

自习室预订系统|基于springboot框架+ Mysql+Java+B/S架构的自习室预订系统设计与实现(可运行源码+数据库+设计文档+部署说明)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 学生功能模块 管理员功能登录前台功能效果图 系统功能设计 数据库E-R图设计 lunwen参…

蓝桥真题——-小蓝重组质数(全排列和质数判断)

小蓝有一个十进制正整数n&#xff0c;其不包含数码0&#xff0c;现在小蓝可以任意打乱数码的顺序&#xff0c;小蓝想知道通过打乱数码顺序,n 可以变成多少个不同的质数。 #include <iostream> #include<bits/stdc.h> using namespace std; bool isprime(int n) {if…

51单片机LED8*8点阵显示坤坤跳舞打篮球画面

我们作为一名合格的 ikun&#xff0c;专业的小黑子&#xff0c;这个重要的知识必须学会。 先看效果&#xff1a; 51LED点阵_鸡你太美 这里我们首先要用到延时函数Delay&#xff1a; void Delay(unsigned int xms) {unsigned char i, j;while(xms--){ i 2;j 239;do{while (-…

NodeJs利用腾讯云实现手机发送验证码

本文介绍如何在nodejs实现短信发送&#xff0c;以腾讯云的短信验证为例。 腾讯云中准备工作 首先需要腾讯云的个人或者企业认证的账号&#xff0c;个人会赠送一百条&#xff0c;企业赠送一千条&#xff0c;可以用于测试&#xff0c;地址&#xff1a;腾讯云短信服务。然后需要…

计算点集的最小外接矩形——OpenCV的minAreaRect函数

计算点集的最小外接矩形——OpenCV的minAreaRect函数 函数原型 输入一系列二维点&#xff0c;返回其最小外接矩形。 RotatedRect minAreaRect( InputArray points );根据函数原型&#xff0c;输入的数据可以是vector<Point>类型&#xff0c;包含1个以上的点&#xff1…

Redis:ClassCastException【bug】

Redis&#xff1a;ClassCastException【bug】 前言版权Redis&#xff1a;ClassCastException【bug】错误产生相关资源控制器&#xff1a;UserController("/user")配置&#xff1a;RedisConfiguration实体类&#xff1a;User数据表&#xff1a;User 解决 最后 前言 2…

BMP280学习

1.Forced mode模式&#xff0c;单次采集后进入休眠&#xff0c;适用于低采样率。 2.normal mode模式&#xff0c;持续采集&#xff0c;我们使用这种 采集事件基本都是ms级&#xff0c;所以我们1s更新一次。 温度和压力的计算 #include <SPI.h> //定义数据类型 #define s3…

hadoop单机ssh免密登录

1. 在hadoop目录下生成密钥对 [rootmaster centos]# cd /usr/apps/hadoop-2.7.1/ [rootmaster hadoop-2.7.1]# ssh-keygen -t rsa //在hadoop目录下生成密钥对 2.找到密钥对的位置 [rootmaster hadoop-2.7.1]# find / -name .ssh //找到密钥对的位置 cd [rootmaster hadoo…