Spring Cloud Gateway学习记录

news2024/9/26 3:20:57

Spring中文网 https://springdoc.cn/spring-cloud-gateway/

Spring官网 https://spring.io/projects/spring-cloud-gateway

网关简介

大家都都知道在微服务架构中,一个系统会被拆分为很多个微服务。那么作为客户端要如何去调用这么多的微服务呢?

如果没有网关的存在,我们只能`在客户端记录每个微服务的地址,然后分别去用。

这样的架构,会存在着诸多的问题:

  • 每个业务都会需要鉴权、限流、权限校验、跨域等逻辑,如果每个业务都各自为战,自己造轮子实现一遍,会

很蛋疼,完全可以抽出来,放到一个统一的地方去做。

  • 如果业务量比较简单的话,这种方式前期不会有什么问题,但随着业务越来越复杂,比如淘宝、亚马逊打开一

个页面可能会涉及到数百个微服务协同工作,如果每一个微服务都分配一个域名的话,一方面客户端代码会很难维

护,涉及到数百个域名,另一方面是连接数的瓶颈,想象一下你打开一个APP,通过抓包发现涉及到了数百个远程

调用,这在移动端下会显得非常低效。

  • 后期如果需要对微服务进行重构的话,也会变的非常麻烦,需要客户端配合你一起进行改造,比如商品服务,

随着业务变的越来越复杂,后期需要进行拆分成多个微服务,这个时候对外提供的服务也需要拆分成多个,同时需

要客户端配合你进行改造,非常蛋疼。

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


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

添加上API网关之后,系统的架构图变成了如下所示:

我们也可以观察下,我们现在的整体架构图:

1. 什么是Spring Cloud Gateway

网关作为流量的入口,常用的功能包括路由转发,权限校验,限流等。

Spring Cloud Gateway 是Spring Cloud官方推出的第二代网关框架,定位于取代 Netflix Zuul1.0。相比 Zuul 来说,Spring CloudGateway 提供更优秀的性能,更强大的有功能。

Spring Cloud Gateway 是由 WebFlux + Netty + Reactor 实现的响应式的 API 网关。它不能在传统的 servlet 容器中工作,也不能构建成 war 包。

Spring Cloud Gateway 旨在为微服务架构提供一种简单且有效的 API 路由的管理方式,并基于 Filter 的方式提供网关的基本功能,例如说安全认证、监控、限流等等。

其他的网关组件:

在SpringCloud微服务体系中,有个很重要的组件就是网关,在1.x版本中都是采用的Zuul网关;但在2.x版本中,zuul的升级一直跳票,SpringCloud最后自己研发了一个网关替代Zuul,那就是SpringCloud Gateway

网上很多地方都说Zuul是阻塞的,Gateway是非阻塞的,这么说是不严谨的,准确的讲Zuul1.x是阻塞的,而在2.x的版本中,Zuul也是基于Netty,也是非阻塞的,如果一定要说性能,其实这个真没多大差距。

而官方出过一个测试项目,创建了一个benchmark的测试项目:spring-cloud-gateway-bench,其中对比了:

性能强劲:是第一代网关Zuul的1.6倍

官网文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories

Spring Cloud Gateway 功能特征

  • 基于Spring Framework 5, Project Reactor 和 Spring Boot 2.0 进行构建;
  • 动态路由:能够匹配任何请求属性;
  • 支持路径重写;
  • 集成 Spring Cloud 服务发现功能(Nacos、Eruka);
  • 可集成流控降级功能(Sentinel、Hystrix);
  • 可以对路由指定易于编写的 Predicate(断言)和 Filter(过滤器);
1.1 核心概念
  • 路由(route)

路由是网关中最基础的部分,路由信息包括一个ID、一个目的URI、一组断言工厂、一组Filter组成。如果断言为真,则说明请求的URL和

配置的路由匹配。

  • 断言(predicates)

Java8中的断言函数,SpringCloud Gateway中的断言函数类型是Spring5.0框架中的ServerWebExchange。断言函数允许开发者去定义

匹配Http request中的任何信息,比如请求头和参数等。

  • 过滤器(Filter)

SpringCloud Gateway中的filter分为Gateway FilIer和Global Filter。Filter可以对请求和响应进行处理。

1.2 工作原理

执行流程大体如下:

  1. Gateway Client向Gateway Server发送请求
  2. 请求首先会被HttpWebHandlerAdapter进行提取组装成网关上下文
  3. 然后网关的上下文会传递到DispatcherHandler,它负责将请求分发给RoutePredicateHandlerMapping
  4. RoutePredicateHandlerMapping负责路由查找,并根据路由断言判断路由是否可用
  5. 如果过断言成功,由FilteringWebHandler创建过滤器链并调用
  6. 请求会一次经过PreFilter–微服务–PostFilter的方法,最终返回响应

2. Spring Cloud Gateway快速开始

2.1 环境搭建
  1. 引入依赖
 <!‐‐ gateway网关 ‐‐>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring‐cloud‐starter‐gateway</artifactId>
</dependency>

注意:会和spring-webmvc的依赖冲突,需要排除spring-webmvc

2.编写yml配置文件

server:
  port: 8888
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: product_route # 当前路由的标识, 要求唯一
          uri: http://localhost:8081 # 请求要转发到的地址
          order: 1 # 路由的优先级,数字越小级别越高
          predicates: # 断言(就是路由转发要满足的条件)
            - Path=/product-serv/** # 当请求路径满足Path指定的规则时,才进行路由转发
          filters: # 过滤器,请求在传递过程中可以通过过滤器对其进行一定的修改
            - StripPrefix=1 # 转发之前去掉1层路径.

集成Nacos

现在在配置文件中写死了转发路径的地址, 前面我们已经分析过地址写死带来的问题, 接下来我们从注册中心获取此地址。

  1. 引入依赖
<!‐‐ nacos服务注册与发现 ‐‐>
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring‐cloud‐starter‐alibaba‐nacos‐discovery</artifactId>
</dependency>

编写yml配置文件

server:
  port: 8888
spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
        - id: product_route
          uri: lb://service-product # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
          predicates:
            - Path=/product-serve/**
          filters:
            - StripPrefix=1

简写: 去掉关于路由的配置,自动寻找服务

server:
  port: 8888
spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true

3)测试

这时候,就发现只要按照网关地址/微服务/接口的格式去访问,就可以得到成功响应。

2.2 路由断言工厂(Route Predicate Factories)配置

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories

作用: 当请求gateway的时候, 使用断言对请求进行匹配, 如果匹配成功就路由转发, 如果匹配失败就返回404

类型:内置,自定义

SpringCloud Gateway包括许多内置的断言工厂,所有这些断言都与HTTP请求的不同属性匹配。具体如下:

  • 基于Datetime类型的断言工厂

此类型的断言根据时间做判断,主要有三个:

AfterRoutePredicateFactory: 接收一个日期参数,判断请求日期是否晚于指定日期

BeforeRoutePredicateFactory: 接收一个日期参数,判断请求日期是否早于指定日期

BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间段内

ZonedDateTime.now()

‐ After=2019‐12‐31T23:59:59.789+08:00[Asia/Shanghai]
  • 基于远程地址的断言工厂

RemoteAddrRoutePredicateFactory:接收一个IP地址段,判断请求主机地址是否在地址段中

‐ RemoteAddr=192.168.1.1/24
  • 基于Cookie的断言工厂

CookieRoutePredicateFactory:接收两个参数,cookie 名字和一个正则表达式。 判断请求

cookie是否具有给定名称且值与正则表达式匹配。

‐Cookie=chocolate, ch.
  • 基于Header的断言工厂

HeaderRoutePredicateFactory:接收两个参数,标题名称和正则表达式。 判断请求Header是否具有给定名称且值与正则表达式匹配。

 ‐Header=X‐Request‐Id, \d+
  • 基于Host的断言工厂

HostRoutePredicateFactory:接收一个参数,主机名模式。判断请求的Host是否满足匹配规则。

‐Host=**.testhost.org
  • 基于Method请求方法的断言工厂

MethodRoutePredicateFactory:接收一个参数,判断请求类型是否跟指定的类型匹配。

 ‐Method=GET
  • 基于Path请求路径的断言工厂

PathRoutePredicateFactory:接收一个参数,判断请求的URI部分是否满足路径规则。

‐Path=/foo/{segment}
  • 基于Query请求参数的断言工厂

QueryRoutePredicateFactory :接收两个参数,请求param和正则表达式, 判断请求参数是否具有给定名称且值与正则表达式匹配。

‐Query=baz, ba.
  • 基于路由权重的断言工厂

WeightRoutePredicateFactory:接收一个[组名,权重], 然后对于同一个组内的路由按照权重转发

routes:
 ‐id: weight_route1
 uri: host1
 predicates:
 ‐Path=/product/**
 ‐Weight=group3, 1
 ‐id: weight_route2
 uri: host2
 predicates:
 ‐Path=/product/**
 ‐Weight= group3, 9

2.2.5 自定义路由断言工厂

自定义路由断言工厂需要继承 AbstractRoutePredicateFactory 类,重写 apply 方法的逻辑。在 apply 方法中可以通过

exchange.getRequest() 拿到 ServerHttpRequest 对象,从而可以获取到请求的参数、请求方式、请求头等信息。

必须spring组件 bean

类必须加上**RoutePredicateFactory**作为结尾

必须继承**AbstractRoutePredicateFactory**

必须声明静态内部类 声明属性来接收 配置文件中对应的断言的信息

需要结合**shortcutFieldOrder**进行绑定

通过apply进行逻辑判断 true就是匹配成功 false匹配失败

注意: 命名需要以 RoutePredicateFactory 结尾

@Component
@Slf4j
public class CheckAuthRoutePredicateFactory extends AbstractRoutePredicateFactory<CheckAuthRoutePredicateFactory.Config> {
    public CheckAuthRoutePredicateFactory() {
        super(Config.class);
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {

            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                log.info("调用CheckAuthRoutePredicateFactory" + config.getName());
                if (config.getName().equals("xushu")) {
                    return true;
                }
                return false;
            }
        };
    }

    /**
     * 快捷配置
     * @return
     */
    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("name");
    }

    public static class Config {

        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

yml中配置

spring:
  cloud:
    gateway:
      #设置路由:路由id、路由到微服务的uri、断言
      routes:
        - id: order_route #路由ID,全局唯一
          uri: http://localhost:8020 #目标微服务的请求地址和端口
          predicates:
          	# 测试:http://localhost:8888/order/findOrderByUserId/1
            - Path=/order/** #Path路径匹配
            #自定义CheckAuth断言工厂
            - CheckAuth=xushu
2.3 过滤器工厂( GatewayFilter Factories)配置

Gateway 内置了很多的过滤器工厂,我们通过一些过滤器工厂可以进行一些业务逻辑处理器,比如添加剔除响应头,添加去除参数等

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories

2.3.1 添加请求头
spring:
  cloud:
    gateway:
      #设置路由:路由id、路由到微服务的uri、断言
      routes:
        - id: order_route #路由ID,全局唯一
          uri: http://localhost:8020 #目标微服务的请求地址和端口
          #配置过滤器工厂
          filters:
            - AddRequestHeader=X-Request-color, red #添加请求头

测试http://localhost:8888/order/testgateway

@GetMapping("/testgateway")
public String testGateway(HttpServletRequest request) throws Exception {
    log.info("gateWay获取请求头X-Request-color:" + request.getHeader("X-Request-color"));
    return "success";
}

@GetMapping("/testgateway2")
public String testGateway(@RequestHeader("X-Request-color") String color) throws Exception {
    log.info("gateWay获取请求头X-Request-color:" + color);
    return "success";
}

2.3.2 添加请求参数
spring:
  cloud:
    gateway:
      #设置路由:路由id、路由到微服务的uri、断言
      routes:
        - id: order_route #路由ID,全局唯一
          uri: http://localhost:8020 #目标微服务的请求地址和端口
          #配置过滤器工厂
          filters:
            - AddRequestParameter=color, blue # 添加请求参数

测试http://localhost:8888/order/testgateway3

@GetMapping("/testgateway3")
public String testGateway3(@RequestParam("color") String color) throws Exception {
    log.info("gateWay获取请求参数color:" + color);
    return "success";
}

2.3.3 为匹配的路由统一添加前缀
spring:
  cloud:
    gateway:
      #设置路由:路由id、路由到微服务的uri、断言
      routes:
        - id: order_route #路由ID,全局唯一
          uri: http://localhost:8020 #目标微服务的请求地址和端口
          #配置过滤器工厂
          filters:
            - PrefixPath=/mall-order # 添加前缀 对应微服务需要配置context-path

mall-order中需要配置

server:
  servlet:
    context-path: /mall-order

测试:http://localhost:8888/order/findOrderByUserId/1 ====》 http://localhost:8020/mall­order/order/findOrderByUserId/1

2.3.4 重定向操作
spring:
  cloud:
    gateway:
      #设置路由:路由id、路由到微服务的uri、断言
      routes:
        - id: order_route #路由ID,全局唯一
          uri: http://localhost:8020 #目标微服务的请求地址和端口
          #配置过滤器工厂
          filters:
            - RedirectTo=302, https://www.baidu.com/ #重定向到百度

测试:http://localhost:8888/order/findOrderByUserId/1

2.3.5 自定义过滤器工厂

继承AbstractNameValueGatewayFilterFactory且我们的自定义名称必须要以GatewayFilterFactory结尾并交给spring管理。

@Component
@Slf4j
public class CheckAuthGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory<NameValueConfig> {

    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return (exchange, chain) -> {
            log.info("调用CheckAuthGatewayFilterFactory===" + config.getName() + ":" + config.getValue());
            return chain.filter(exchange);
        };
    }
}

配置自定义的过滤器工厂

spring:
  cloud:
    gateway:
      #设置路由:路由id、路由到微服务的uri、断言
      routes:
        - id: order_route #路由ID,全局唯一
          uri: http://localhost:8020 #目标微服务的请求地址和端口
          #配置过滤器工厂
          filters:
            - CheckAuth=fox,

测试

2.4 全局过滤器(Global Filters)配置

局部过滤器和全局过滤器区别:

局部:局部针对某个路由, 需要在路由中进行配置

全局:针对所有路由请求, 一旦定义就会投入使用

GlobalFilter 接口和 GatewayFilter 有一样的接口定义,只不过, GlobalFilter 会作用于所有路由。

2.4.1 LoadBalancerClientFilter

LoadBalancerClientFilter 会查看exchange的属性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的值(一个

URI),如果该值的scheme是 lb,比如:lb://myservice ,它将会使用Spring Cloud的LoadBalancerClient 来将 myservice 解析成实

际的host和port,并替换掉 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的内容。

其实就是用来整合负载均衡器Ribbon的

spring:
  cloud:
    gateway:
      routes:
        - id: order_route
          uri: lb://mall-order
          predicates:
            - Path=/order/**
2.4.2 自定义全局过滤器
@Component
public class LogFilter implements GlobalFilter {
    Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info(exchange.getRequest().getPath().value());
        return chain.filter(exchange);
    }
}

Reactor Netty 访问日志

要启用 Reactor Netty 访问日志,请设置­Dreactor.netty.http.server.accessLogEnabled=true.

它必须是 Java 系统属性,而不是 Spring Boot 属性。

您可以将日志记录系统配置为具有单独的访问日志文件。以下示例创建一个 Logback 配置:

例 67.logback.xml

<appender name="accessLog" class="ch.qos.logback.core.FileAppender">
  <file>access_log.log</file>
  <encoder>
    <pattern>%msg%n</pattern>
  </encoder>
</appender>
<appender name="async" class="ch.qos.logback.classic.AsyncAppender">
  <appender-ref ref="accessLog" />
</appender>

<logger name="reactor.netty.http.server.AccessLog" level="INFO" additivity="false">
  <appender-ref ref="async"/>
</logger>
2.5 Gateway跨域配置(CORS Configuration)

通过yml配置的方式

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#cors-configuration

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "*"
            allowedMethods:
              - GET
              - POST
              - DELETE
              - PUT
              - OPTION

通过java配置的方式

@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}
2.6 gateway整合sentinel流控降级

网关作为内部系统外的一层屏障, 对内起到一定的保护作用, 限流便是其中之一. 网关层的限流可以简单地针对不同路由进行限流,

也可针对业务的接口进行限流,或者根据接口的特征分组限流。

https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81

1. 添加依赖

<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

2.添加配置

sentinel:
  transport:
    # 添加sentinel的控制台地址
    dashboard: 127.0.0.1:8080
2.6.1 控制台实现方式:

Sentinel 1.6.3 引入了网关流控控制台的支持,用户可以直接在 Sentinel 控制台上查看 API Gateway 实时的 route 和自

定义 API 分组监控,管理网关规则和 API 分组配置。

从 1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:

  • route 维度:即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeId
  • 自定义 API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组

自定义异常方式:

1.通过yml

spring:cloud.sentinel.scg.fallback.mode = response
spring.cloud.sentinel.scg.fallback.response‐body = '{"code":403,"mes":"限流了"}'

2.通过GatewayCallbackManager

@Configuration
public class GatewayConfig {

    @PostConstruct
    public void init() {
        BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable throwable) {
                return ServerResponse.status(HttpStatus.OK)
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(BodyInserters.fromValue("降级了!"));
            }
        };

        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }
}
2.6.2 代码实现方式:(了解)

用户可以通过 GatewayRuleManager.loadRules(rules) 手动加载网关规则

GatewayConfiguration中添加

@PostConstruct
public void doInit() {
    //初始化网关限流规则
    initGatewayRules();
    //自定义限流异常处理器
    initBlockRequestHandler();
}

private void initGatewayRules() {
    Set<GatewayFlowRule> rules = new HashSet<>();
    //resource:资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称。
    //count:限流阈值
    //intervalSec:统计时间窗口,单位是秒,默认是 1 秒。
    rules.add(new GatewayFlowRule("order_route")
              .setCount(2)
              .setIntervalSec(1)
             );
    rules.add(new GatewayFlowRule("user_service_api")
              .setCount(2)
              .setIntervalSec(1)
             );

    // 加载网关规则
    GatewayRuleManager.loadRules(rules);
}

private void initBlockRequestHandler() {
    BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
        @Override
        public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable t) {
            HashMap<String, String> result = new HashMap<>();
            result.put("code",String.valueOf(HttpStatus.TOO_MANY_REQUESTS.value()));
            result.put("msg", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());
            return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
            .contentType(MediaType.APPLICATION_JSON)
            .body(BodyInserters.fromValue(result));
        }
    };
    //设置自定义异常处理器
    GatewayCallbackManager.setBlockHandler(blockRequestHandler);
}
2.7 网关高可用

为了保证 Gateway 的高可用性,可以同时启动多个 Gateway 实例进行负载,在 Gateway 的上游使用 Nginx 或者 F5 进行负载转发以达到高可用。

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

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

相关文章

如何恢复格式化的 Android 智能手机

如何恢复Android手机上格式化的数据 格式化智能手机的存储卡后&#xff0c;您想恢复图片、视频、音乐吗&#xff1f;您想从 Android 手机中恢复已删除的文本吗&#xff1f;格式化存储卡后&#xff0c;如何恢复存储卡上的图片&#xff1f; 使用奇客数据恢复&#xff0c;这款特…

可解释人工智能(XAI)领域的全面概述

AI 模型&#xff0c;尤其是深度学习模型&#xff0c;由于其黑盒性质&#xff0c;在安全关键领域&#xff08;如医疗保健、金融和自动驾驶汽车&#xff09;中面临着重大挑战。用户无法理解模型的内部逻辑和决策过程&#xff0c;这导致了缺乏信任、透明度和问责制。XAI 通过提供模…

C的温故而知新:The Last(C Primer Plus第十六、十七章)

The Last 想必是后面的内容超出大一课程规定的内容了&#xff0c;后面的文章数据惨的可怜。搜一下就能看见&#xff0c;好多人主张这本书后面几张可以不看。咋讲呢&#xff0c;对于这个观点来说&#xff0c;我本人是不认同的&#xff0c;我呢&#xff0c;粗略的看了看后两章的…

降Compose十八掌之『羝羊触蕃』| Handle Platform Lifecycles

公众号「稀有猿诉」 原文链接 降Compose十八掌之『羝羊触蕃』| Handle Platform Lifecycles Jetpack Compose是一个独立的声明式UI框架&#xff0c;它并不受限于任何操作系统平台&#xff0c;从框架定位的角度来讲&#xff0c;它是跨平台的&#xff0c;也应该要跨平台。…

Mail PHP: 如何设置SMTP服务器以发送邮件?

Mail PHP的功能怎么有效配置&#xff1f;Mail PHP的性能如何优化&#xff1f; 无论是用户注册确认、密码重置&#xff0c;还是系统通知&#xff0c;邮件发送功能都是不可或缺的。在PHP中&#xff0c;使用SMTP服务器发送邮件是一种高效且可靠的方式。AokSend将详细介绍如何在Ma…

如何通过HARQ确定新传和重传?

有朋友对如何通过HARQ判断是否是新传还是重传有疑问&#xff0c;这里就简单整理下相关内容。 先看下DL 新传和重传是如何判定的。 HARQ process根据DCI 中的New data indicator(NDI) field指示来判定接收的TB块是新传还是重传block&#xff1a; 1 相同HARQ id &#xff0c;相比…

【C++ 面试 - STL】每日 3 题(九)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…

开学季有什么必备好物?这篇好物推荐不要错过!

随着开学季节的来临&#xff0c;众多商家纷纷推出一系列的优惠活动&#xff0c;这使得开学季成为了购物的理想时机。无论是电子产品还是日常用品&#xff0c;此时购买都非常合算。下面&#xff0c;我将为大家推荐几款开学季不可或缺的好物。开学季有什么必备好物&#xff1f;如…

AI艺术创作福利:免费领取红包封面,Meo喵、龙小金与你共庆佳节!

&#x1f389;&#x1f409;&#x1f431; 亲爱的朋友们&#xff0c;佳节将至&#xff0c;北京时间24年9月6日18:00&#xff0c;我们通过Midjourney的AI艺术创作和ComfyUI设计&#xff0c;特别为大家准备了一份特别的礼物——1588个独家设计的微信红包封面&#xff01;欢迎关注…

2024年全国大学生数学建模比赛思路、题目、代码

竞赛时间及参赛建议 竞赛开始时间&#xff1a;北京时间2024年9月5日18:00 竞赛结束时间&#xff1a;北京时间2024年9月8日20:00 关于今年每道题的思路&#xff0c;可以关注我gzh回复”国赛A/B/C/D/E题“获取 需要帮助的可以关注公众号&#xff0c;在功能栏点击联系我们&…

利用大模型实时提取和检索多模态数据探索-利用 Indexify 进行文档分析

概览 传统的文本提取方法常常无法理解非结构化内容&#xff0c;因此提取数据的数据往往是错误的。本文将探讨使用 Indexify&#xff0c;一个用于实时多模态数据提取的开源框架&#xff0c;来更好地分析pdf等非结构化文件。我将介绍如何设置 Indexify&#xff0c;包括服务器设置…

智能设计#生成式海报

终于有机会把智能海报&#xff0c;做个升级了。比几年前的做法优雅了很多&#xff0c;也没有了素材有限的困扰。1 点一次&#xff0c;生成4张图2 选1张图&#xff0c;点海报生成3 得到封面海报

vue----一维数组根据同一id改成二维数组

vue----一维数组根据同一id改成二维数组 初始数据&#xff08;多个dimension_id值一样&#xff09;&#xff1a; 转换后的数据&#xff08;类似于&#xff09;&#xff1a; [{dimension_id: xxxxxxxxx,desc: 111,res: [{ id: 4444444, self_score: 90 },{ id: 5555555, sel…

PulseSensor心率传感器详解(STM32)

目录 一、介绍 二、传感器原理 1.接线图 2.引脚描述 3.工作原理&#xff1a;光电容积法原理 4.工作原理&#xff1a;心率采样数据处理算法 三、程序设计 main.c文件 adcx.h文件 adc.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 PulseSensor传感器是一种基…

4.1 溪降技术:峡谷等级规划

Content 4.1 溪降技术&#xff1a;峡谷等级规划概述观看视频课程电子书&#xff1a;峡谷等级评定FFME&#xff08;法国&#xff09;系统FFME等级评定系统 - 工作原理垂直特征或“V”等级水特征或“A”等级难度/持续时间 ACA&#xff08;美国&#xff09;等级评定系统ACA等级评定…

啊!FLUX 模型爆火,电商人爱死!好用快冲!

今天&#xff0c;我来分享一批FLUX模型搭配使用的LORA&#xff0c;可能有些朋友不太了解FLUX模型&#xff0c;这里也做快速做个简要介绍&#xff1a;FLUX模型是在2024年8月1日发布的。这款模型出自Black Forest Labs之手&#xff0c;其团队正是Stable Diffusion的原班人马&…

PCI Express 体系结构导读摘录(三)

系列文章目录 PCI Express 体系结构导读摘录&#xff08;一&#xff09; PCI Express 体系结构导读摘录&#xff08;二&#xff09; PCI Express 体系结构导读摘录&#xff08;三&#xff09; 文章目录 系列文章目录第 6 章  PCIe 总线的事务层6. 1  TLP 的格式6. 1. 1 通用 …

【运维自动化-作业平台】如何快速执行脚本和分发文件

脚本执行和文件分发是作业平台最基本、最核心的两个原子功能&#xff0c;主要分页面快速执行和作业里步骤引用&#xff0c;使用逻辑一样&#xff0c;一起来看看具体如何使用快速执行脚本 核心实现原理就是基于gse的命令管道&#xff0c;把脚本内容以WebPortal的方式透传到目标…

基于yolov8的口罩佩戴检测系统python源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv8的口罩佩戴检测系统是一款利用深度学习技术&#xff0c;特别是YOLOv8算法&#xff0c;实现高效、准确检测人脸是否佩戴口罩的系统。YOLOv8作为YOLO系列算法的最新版本&#xff0c;在检测速度和准确性上进行了显著优化&#xff0c;能够实时处理图像和视…

UDP协议程序设计

文章目录 前言一、UDP程序设计是什么&#xff1f;二、使用步骤 1.数据包套接字与多播套接字2.数据报包3.实操展示总结 前言 UDP协议程序相对于TCP协议&#xff0c;就是一个广播喇叭给全村人听和两个人说悄悄话的差别。因此UDP的数据传输效率比TCP高&#xff0c;可以同时分享给所…