springcloud:4.1 GateWay

news2025/1/9 16:31:19

概述

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;
    }
}
          

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

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

相关文章

MM1: Methods, Analysis Insights from Multimodal LLM Pre-training

MM1: Methods, Analysis & Insights from Multimodal LLM Pre-training 相关链接&#xff1a;arxiv 关键字&#xff1a;多模态学习、大型语言模型、预训练、视觉语言连接、混合专家模型 摘要 本文讨论了构建高性能的多模态大型语言模型&#xff08;MLLMs&#xff09;。特别…

OPTIONS请求(跨域预检查)

目录 一、什么是OPTIONS请求&#xff1f;二、简单请求、复杂请求三、特定的请求头、响应头 一、什么是OPTIONS请求&#xff1f; OPTIONS 请求方式是 HTTP 协议中的一种&#xff0c;主要用于 从响应头中获取服务器支持的HTTP请求方式。 OPTIONS 请求方式是 浏览级行为&#xf…

【SpringCloud微服务实战02】Ribbon 负载均衡

Ribbon使用 Eureka中已经集成了Ribbon,无需额外引入,通过 @LoadBalanced 注解在请求中使用 Ribbon 负载均衡: @Bean @LoadBalancedpublic RestTemplate restTemplate() {return new RestTemplate(); } Ribbon工作流程图 Ribbon负载均衡策略 修改Ribbon负载均衡策略 方式一…

从0开始启动一个Django的docker服务

本文是从0开始启动一个Django的docker服务&#xff0c;包括构建镜像,uwsgi启动服务 在服务器上安装ssh&#xff0c;git&#xff0c;生成公钥并复制到服务器上 # 安装ssh yum install openssh-clients # 生成sshkey ssh-keygen # 查看公钥 cat /root/.ssh/id_rsa.pubclone一下…

Text-to-SQL 工具Vanna | 查看训练数据、删除训练数据

1.查看训练数据vn.get_training_data vn.get_training_data 源码如下&#xff0c;可以看到返回的是df格式的数据 abstractmethoddef get_training_data(self, **kwargs) -> pd.DataFrame:"""Example:pythonvn.get_training_data()This method is used to ge…

Brute Force 算法介绍

Brute Force 算法介绍 Brute Force 算法&#xff1a;简称为 BF 算法。中文意思是暴力匹配算法&#xff0c;也可以叫做朴素匹配算法。 BF 算法思想&#xff1a;对于给定文本串 T 与模式串 p&#xff0c;从文本串的第一个字符开始与模式串 p 的第一个字符进行比较&#xff0c;如果…

计算机考研|408专业课复习教程+注意事项

408其实把真题琢磨透就已经可以了&#xff01;其实大部分考研党复习到最后真题都来不及刷完就要上考场 因为在考研后期时间分配真的很困难&#xff01;特别是数学和408 本人双非科班出身备考408成功上岸&#xff0c;在这里也想给想考408的学弟学妹们一些很中肯的&#xff0c;…

干重活儿的互联网

接女儿放学路过欧尚超市&#xff0c;我说 “十年前我每周末推着小车带你去超市&#xff0c;那时没有这么多送外卖的&#xff0c;什么东西都要自己跑过去买”&#xff0c;“你的意思是要表达科技获得很大进步了吗&#xff1f;” 女儿反问&#xff0c;“不&#xff0c;恰恰相反&a…

FTP协议的工作原理:探索端口21的角色

FTP协议的工作原理&#xff1a;探索端口21的角色 在网络协议的众多家族中&#xff0c;文件传输协议&#xff08;FTP&#xff09;以其稳定性和高效性在文件上传和下载领域占有一席之地。FTP的设计允许用户在客户端和服务器之间进行文件传输&#xff0c;而理解其背后的端口机制是…

<JavaEE> 了解网络层协议 -- IP协议

目录 初识IP协议 什么是IP协议&#xff1f; IP协议中的基础概念 IP协议格式 图示 4bit版本号&#xff08;version&#xff09; 4bit头部长度&#xff08;headerlength&#xff09; 8bit服务类型&#xff08;TypeOfService&#xff09; 16bit总长度&#xff08;total l…

Java面试——SQL 语句题

优质博文&#xff1a;IT-BLOG-CN 一、行转列问题 现有表格A&#xff0c;按照以下格式排列&#xff1b; 姓名收入类型收入金额Tom年奖金5wTom月工资10kJack年奖金8wJack月工资12k 先需要将表格转化为&#xff1a; 姓名月工资年奖金Tom10k50kJack12k80k 方法一&#xff1a;…

C语言-strstr(字符串里查找字符串)

strstr&#xff08;字符串里查找字符串&#xff09; 语法格式 库函数实现的逻辑 1&#xff0c;返回一个指向str2在str1中第一次出现的位置&#xff0c;如果str2不是p&#xff0c;则返回一个空指针&#xff0c;函数返回字符串str2在字符串str1中第一次出现的位置) 2&#xf…

SpringBoot3项目框架搭建

注意jdk版本必须17以上才能运行 1、创建Maven工程 2、导入spring-boot-stater-web起步依赖 3、编写Controller 4、提供启动类 5、访问http://localhost:8080/hello

计算机丢失vcruntime140.dll解决办法分享,有效解决vcruntime140.dll丢失问题

vcruntime140.dll是一个属于 Visual C Redistributable for Visual Studio 2015 的动态链接库文件。这个文件是运行那些用 Visual Studio 2015 或相关版本开发的 C 应用程序必不可少的一部分。如果系统中缺少此文件&#xff0c;或文件损坏&#xff0c;则可能会在尝试启动相关软…

[【Hello,PyQt】pyqt5中的QLineEdit控件

PyQt5 是一个强大的Python库&#xff0c;用于创建图形用户界面&#xff08;GUI&#xff09;。其中&#xff0c;QLineEdit 控件作为一个简单而实用的组件&#xff0c;经常用于接受用户的单行文本输入&#xff0c;甚至可以用来进行输入格式的限制。这篇博客中将介绍 QLineEdit 控…

react-native使用FireBase实现google登陆

一、前置操作 首先下载这个包 yarn add react-native-google-signin/google-signin 二、Google cloud配置 Google Cloud 去google控制台新建一个android项目&#xff0c;这时候需要用到你自己创建的keystore的sha1值&#xff0c;然后会让你下载一个JSON文件&#xff0c;先保…

【电路笔记】-金属氧化物半导体晶体管(MOSFET)

金属氧化物半导体晶体管(MOSFET) 文章目录 金属氧化物半导体晶体管(MOSFET)1、概述2、MOSFET 基本结构和符号2.1 耗尽型 MOSFET2.2 增强型MOSFET3、MOSFET放大器4、总结1、概述 除了结型场效应晶体管 (JFET) 之外,还有另一种类型的场效应晶体管,其栅极输入与主载流通道电绝缘…

计算机网络—VLAN 配置

目录 1.拓扑图 2.实验环境准备 2.关闭不相关接口&#xff0c;并配置 Trunk 3.创建 VLAN 4.为客户端配置 IP地址 5.检测设备连通性&#xff0c;验证 VLAN 配置结果 6.配置 Hybrid 端口 7.配置文件 1.拓扑图 2.实验环境准备 在S1和S2上创建Eth-Trunk 1并配置该Eth-Trunk…

JVM-5

1.选择垃圾收集器 如果你的堆大小不是很大&#xff08;比如 100MB &#xff09;&#xff0c;选择串行收集器一般是效率最高的。 参数&#xff1a; -XX:UseSerialGC 。如果你的应用运行在单核的机器上&#xff0c;或者你的虚拟机核数只有单核&#xff0c;选择串行收集器依然是合…

17-指针(初识)

17-1 内存 内存是电脑上特别重要的存储器&#xff0c;计算机中程序的运行都是在内存中进行的。 为了有效的使用内存&#xff0c;就把内存划分成一个个小的内存单元&#xff0c;每个内存单元的大小是1个字节。为了能够有效的访问到内存的每个单元&#xff0c;就给内存单元进行…