九、Spring Cloud—gateway网关

news2024/11/24 9:55:51

一、引言

每个微服务都需和前端进行通信,解决每个微服务请求时的鉴权、限流、权限校验、跨域等逻辑,放在一个统一的地方进行使用。

在微服务架构中,网关是一个重要的组件,它作为系统的入口,负责接收所有的客户端请求,并将请求路由到相应的微服务。

网关的作用主要有以下几点:

  1. 统一入口:网关作为系统的唯一入口,可以为客户端提供一个统一的接口,简化了客户端的调用过程。

  2. 路由转发:网关可以根据请求的 URL 和参数等信息,将请求路由到对应的微服务,实现请求的转发。

  3. 负载均衡:网关可以通过负载均衡算法,将请求分发到不同的微服务实例上,提高了系统的性能和可用性。

  4. 安全控制:网关可以对请求进行鉴权、过滤和监控等操作,保障了系统的安全性和稳定性。

  5. 缓存管理:网关可以将一些常用的请求结果进行缓存,减少对后端服务的访问,提高了系统的响应速度。

在这里插入图片描述

二、什么是Spring Cloud Gateway

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

Spring cloud Gateway 是Spring Cloud官方推出的第二代网关框架,定位于取代 Netflix Zuul 1.0来说,Spring Cloud Gateway 提供更优秀的性能,更强大的有功能。使用spring boot 2.0构建。

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

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

源码:https://github.com/spring-cloud/spring-cloud-gateway
官网文档:https://spring.io/projects/spring-cloud-gateway

特征
Spring Cloud Gateway具有以下特点:

  • 基于 Spring Framework 5、Project Reactor 和 Spring Boot 2.0 构建。
  • 动态路由:能够匹配任何请求属性。
  • 支持路径重写。
  • 集成Spring Cloud 服务发现功能(Nacos、Eruka)。
  • 可继承流控降级功能你(sentinel、Hystrix)。
  • 可以对路由指定已与编写的Predicate(断言)和Filter(过滤器)。

核心概念

  • 路由 (route)。
    路由是网关中最基础的部分,路由信息包括一个ID、一个目的URI、一组断言工厂、一组Filter组成,如果新言为真,则说明请求的URL和配置的路由匹配。
  • 断言(predicdtes)。
    Java8中的断言函数,SpingCloud Gateway中的断言数类型是Spring5.0架中的ServerWebExchange,断言函数允许开发者去定义匹配http request中的任何信息,比如请求头和参数等。
  • 过滤器 (Filter)。
    SpringCloud Gateway中的filter分为Gateway Filter和Global Filter。Filter可以对请求和响应进行处理。

三、Spring Cloud Gateway快速开始

1、添加依赖-gateway和nacos

    <dependencies>
        <!-- spring cloud gateway 依赖 -->
        <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>
    </dependencies>

如果父级有spring-boot-start-web,需删除,删除spring-boot-start-web依赖项。

因为spring cloud gateway是基于webflux的,如果非要web支持的话需要导入spring-boot-starter-webflux而不是spring-boot-start-web。

2、resources/application.yml配置文件配置gateway和nacos

server:
  port: 8814

spring:
  application:
    name: api-gateway
  #gateway配置
  cloud:
    gateway:
      #路由规则
      routes:
        # 系统模块
        #id 路由的唯一标识
        - id: order-service
          #需要转发的地址 lb:使用 nacos 中本地負載均衡策略
          # order-service 服務名
          uri: lb://order-service
          #断言,用于路由规则的匹配,匹配的路径
          predicates:
            - Path=/order-service/** #指定前缀路由
            # http://localhost:8814/order-service/order/test 路由到
            # http://localhost:8815/order-service/order/test

          #过滤器,去除一级路径  order-service
          #最终变成 http://localhost:8815/order/test 进行请求
          filters:
            - StripPrefix=1
          #- id
    #配置nacos      
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos
          

也可以简写为:

server:
  port: 8814

spring:
  application:
    name: api-gateway
  #gateway配置
  cloud:
    gateway:
      discovery:
        locator:
          #启动自动识别nacos服务。即服务名为第一路径
          enabled: true
    #配置nacos
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos

请求接口测试:
http://localhost:8814/order-service/order/test
和http://localhost:8815/order/test为一个接口。

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

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

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

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

1. 基于Datetime类型的断言工厂
此类型的断言根据时间做判断,主要有三个:

AfterRoutePredicateFactory: 接收一个日期参数,判断请求日期是否晚于指定日期。
BeforeRoutePredicateFactory: 接收一个日期参数,判断请求日期是否早于指定日期。
BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间段内。
ZonedDateTime.now(); 可以输出当前日期格式。

- After=2023-05-30T00:24:56.119+08:00[Asia/Shanghai]
- 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]

2. 基于远程地址的断言工厂
RemoteAddrRoutePredicateFactory: 接收一个P地址段,判断请求主机地址是否在地址段中。

- RemoteAddr=192.168,1.1/24

3. 基于Cookie的断言工厂
CookieRoutePredicateFactory: 接收两个参数,ookie 名字和一个正则表达式。判断请求cookie是否具有给定名称且值与正则表达式匹配。

 -Cookie=chocolate,ch.

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

-Header=X-Request-Id,\d+

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

- Host=**.somehost.org,**.anotherhost.org

6. 基于路由-常用

routes:
      - id: method_route
        uri: https://example.org
        predicates:
        - Method=GET,POST
        - Path=/red/{segment},/blue/{segment}
        - Query=green #指定参数
        - RemoteAddr=192.168.1.1/24  #指定Ip

7. 基于权重

spring:
  cloud:
    gateway:
      routes:
      - id: weight_high
        uri: https://weighthigh.org
        predicates:
        - Weight=group1, 8 #分组,80%的权重
      - id: weight_low
        uri: https://weightlow.org
        predicates:
        - Weight=group1, 2

8. 自定义路由断言工厂
自定义路由断言工厂需要继承 AbstractRoutePredicateFactory类,重写 apply 方法的逻辑。在apply方法可以通过exchange.getRequest()拿到serverHttpRequest对象,从而可以获取到请求的参数、请求方式、请求头等信息。
步骤:

  1. 必须spring组件 bean
  2. 类必须加上RoutePredicateFactory 作为结尾
  3. 必须继承 AbstractRoutePredicateFactory
  4. 必须声明静态内部类声明属性来接收配置文件中对应的断言的信息
  5. 需要结合shortcutFieldOrder进行绑定
  6. 通过apply进行逻辑判断 true就是匹配成 false匹配失败

可以借鉴 QueryRoutePredicateFactory 源码实现自定义的路由断言工厂。
1、代码CheckAuthRoutePredicateFactory

package com.tc.gateway.config;

import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;

import javax.validation.constraints.NotEmpty;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;


@Component
public class CheckAuthRoutePredicateFactory extends AbstractRoutePredicateFactory<CheckAuthRoutePredicateFactory.Config> {

    public CheckAuthRoutePredicateFactory() {
        super(CheckAuthRoutePredicateFactory.Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("name");
    }

    @Override
    public Predicate<ServerWebExchange> apply(CheckAuthRoutePredicateFactory.Config config) {
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange exchange) {
            //简单案例,判断配置文件中CheckAuth是否等于tc
                if(config.getName().equals("tc")){
                    return true;
                }
                return false;
            }

        };
    }

    //用于接收断言中的配置信息
    @Validated
    public static class Config {
        private String name;

        public String getName() {
            return name;
        }

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

2、配置文件。- CheckAuth=tc为自定义的断言信息

server:
  port: 8814

spring:
  application:
    name: api-gateway
  #gateway配置
  cloud:
    gateway:
      #路由规则
      routes:
        # 系统模块
        #id 路由的唯一标识
        - id: order-service
          #需要转发的地址 lb:使用 nacos 中本地負載均衡策略
          # order-service 服務名
          uri: lb://order-service
          #断言,用于路由规则的匹配,匹配的路径
          predicates:
            - Path=/order-service/** #指定前缀路由
            # http://localhost:8814/order-service/order/test 路由到
            # http://localhost:8815/order-service/order/test
#            - After=2023-05-30T00:24:56.119+08:00[Asia/Shanghai] #在该时间之前能够访问,之后直接404
#            - Header=X-Request-Id,\d+ #需在请求头加入key为X-Request-Id,value为数字
#            - Method=GET,POST #请求方式,支持get和post
#            - Query=name #接口需加入参数?name  案例:http://localhost:8815/order-service/order/test?name
#            - Query=name,tc|test #限定值只能是tc或者test  案例:http://localhost:8815/order-service/order/test?name=tc
            - CheckAuth=tc

          #过滤器,去除一级路径  order-service
          #最终变成 http://localhost:8815/order/test 进行请求
          filters:
            - StripPrefix=1
          #- id
    #配置nacos
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos

五、过滤器

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

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

1、局部过滤器
1.1 内置过滤器
内置的过滤器工厂可以在官网进行查看,使用例如:

spring:
 application:
    name: api-gateway
  cloud:
    gateway:
      routes:
      - id: order-service
        uri: lb://order-service
        filters:
        #设置过滤器工厂,给请求头添加默认参数
        - AddRequestHeader=X-Request-red, blue
        # 添加路径前缀
        - PrefixPath=/mypath
       

在这里插入图片描述
在这里插入图片描述

1.2 自定义过滤器工厂
和自定义路由断言工厂类似的结构。

package com.tc.gateway.config;

import com.alibaba.cloud.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;

import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl;

/**
 * @Description: 自定义过滤器工厂
 * @Date: 2023/5/31 22:47
 */
@Component
public class CheckAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<CheckAuthGatewayFilterFactory.Config> {

    public CheckAuthGatewayFilterFactory() {
        super(CheckAuthGatewayFilterFactory.Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("name");
    }

    @Override
    public GatewayFilter apply(CheckAuthGatewayFilterFactory.Config config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                //自己的逻辑处理。简单案例,获取请求中name参数,
                //如果value=设置的值成功,否则失败
                String name = exchange.getRequest().getQueryParams().getFirst("name");
                if(StringUtils.isNotEmpty(name)){
                    if(config.getName().equals(name)){
                    	//正常请求
                        return chain.filter(exchange);
                    }else{
                        //返回404
                        exchange.getResponse().setStatusCode(HttpStatus.NOT_EXTENDED);
                        //结束
                        return exchange.getResponse().setComplete();

                    }
                }
                return chain.filter(exchange);
            }
        };
    }

    public static class Config {

        private String name;

        public String getName() {
            return name;
        }

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

    }

}

配置文件:

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/order-service/** 
          filters:
            - StripPrefix=1
            #自定义的过滤器
            - CheckAuth=tc

2.、全局过滤器

  • 局部过滤器针对某个路由进行过滤,需要在路由中配置。
  • 全局过滤器针对所有路由进行过滤,一旦定义就会投入使用。

授权,权限认证会使用全局过滤器。
在这里插入图片描述
自定义全局过滤器

/**
 * @Description: 全局过滤器
 * @Date: 2023/5/31 23:20
 */
@Component
public class LogFilter implements GlobalFilter {
    Logger log = LoggerFactory.getLogger(LogFilter.class);
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("获取请求的地址"+exchange.getRequest().getPath().value());
        return chain.filter(exchange);
    }
}

测试:

2023-05-31 23:24:04.043  INFO 11244 --- [ctor-http-nio-2] com.tc.gateway.config.LogFilter          : 获取请求的地址/order/test
2023-05-31 23:24:04.968  INFO 11244 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty  : Flipping property: order-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647

六、日志记录

使用Reactor Netty访问日志
要启用Reactor Netty访问日志,需设置
-Dreactor.netty.http.server.accessLogEnabled=true。
可以在IDEA VM options配置-Dreactor.netty.http.server.accessLogEnabled=true即可。
第二行就是Netty访问日志。

2023-06-01 22:41:27.576  INFO 13052 --- [ctor-http-nio-2] com.tc.gateway.config.LogFilter          : 获取请求的地址/order/test
2023-06-01 22:41:27.757  INFO 13052 --- [ctor-http-nio-2] reactor.netty.http.server.AccessLog      : 0:0:0:0:0:0:0:1 - - [01/Jun/2023:22:41:26 +0800] "GET /order-service/order/test HTTP/1.1" 200 17 8814 972 ms
2023-06-01 22:41:28.494  INFO 13052 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty  : Flipping property: order-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647

也可以配置到单独的访问日志文件,使用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>

七、gateway跨域配置(CORS)

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

yml配置方式:

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]': #允许跨域访问的资源
            allowedOrigins: "https://docs.spring.io" #跨域允许来源
            allowedMethods:
            - GET
            - POST

八、gateway整合sentinel

可以针对不同的路由、接口、或者接口的特征分组限流。

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

1、添加依赖

<!-- sentinel整合gateway的依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

<!-- sentinel的依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

2、添加sentinel配置信息

#配置sentinel
spring:
  cloud:
	sentinel:
	  transport:
	    dashboard: 127.0.0.1:8858

启动生成网关的一个路由资源:

该路由资源和配置文件中一致:
  cloud:
    gateway:
      #路由规则
      routes:
        # 系统模块
        #id 路由的唯一标识
        - id: order-service

在这里插入图片描述
通过这个资源即可进行流控。

流控配置界面如下:可以自由灵活配置。
在这里插入图片描述
其中API分组流控,即把接口分层不同的Api组,根据组进行流控,分组之后,点击API分组,可以进行选择分好的组。
设置分组界面如下:
在这里插入图片描述

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

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

相关文章

Shiro高级及SaaS-HRM的认证授权

Shiro高级及SaaS-HRM的认证授权 Shiro在SpringBoot工程的应用 Apache Shiro是一个功能强大、灵活的&#xff0c;开源的安全框架。它可以干净利落地处理身份验证、授权、企业会话管理和加密。越来越多的企业使用Shiro作为项目的安全框架&#xff0c;保证项目的平稳运行。 在之…

前端042_图表展现_自适应

自适应 当缩小窗口时,饼图和柱状图不会自动自适应,会被遮挡住。因为 ECharts 本身并不是自适应的,当你父级容器的宽度发生变化的时候需要手动调用它的 .resize() 方法。 其中 vue-element-admin项目中已经实现了自适应效果,只要将对应代码拷贝引用即可。将 vue-element-adm…

Java中的this、package、import

this 在Java中&#xff0c;this的作用和其词义很接近。 它在方法内部使用&#xff0c;即这个方法所属对象的引用&#xff1b; 它在构造器内部使用&#xff0c;表示该构造器正在初始化的对象。 this 可以调用类的属性、方法和构造器 什么时候使用this关键字呢&#xff…

使用kettle进行日志分析

分析日志是一个大数据分析中较为常见的场景。在Unix类操作系统里&#xff0c;Syslog广泛被应用于系统或者应用的日志记录中。Syslog通常被记录在本地文件内&#xff0c;比如Ubuntu内为/var/log/syslog文件名&#xff0c;也可以被发送给远程Syslog服务器。Syslog日志内一般包括产…

机构的专属的线上招生 教学小程序搭建教程

小程序已经成为了很多教育机构的招生、推广重要渠道之一。相比于传统的网站或APP而言&#xff0c;小程序更加轻量级&#xff0c;更加易于传播和分享。在小程序搭建过程中&#xff0c;无需编写复杂的代码&#xff0c;只需要根据模板进行简单的操作&#xff0c;就可以轻松打造自己…

【Web开发技术】JWT令牌技术(信息安全)

文章目录 一、描述二、依赖三、配置四、java文件中的准备五、开始使用 一、描述 说到JWT令牌技术&#xff0c;就需要提到cookie和session两种技术。这两种技术在跨域问题&#xff08;计算机网络的知识&#xff0c;百度可以搜到&#xff0c;就回归重点&#xff09;上存在一定的局…

《智能新工厂规划白皮书》下 | “四步”规划智能工厂

中国制造业有着最大制造产能、最强配套能力和最大消费市场三个无可比拟的优势&#xff0c;随着产能升级&#xff0c;众企业的新工厂会开展智能工厂规划布局&#xff0c;从而实现降本减耗、提高效益的经营目标&#xff0c;以增强企业市场竞争力。 新工厂规划时&#xff0c;企业…

【GitHub已开源】某博热点事件评论数据分析与用户情感分析平台完整项目

找遍全网无奈只能自己开发某博热点评论数据爬取与用户情感分析平台&#xff0c;这就是技术人的创新&#xff01; 最近想看一下微博热点评论的用户人群情感趋势&#xff0c;想到的就是去爬取某博的评论数据&#xff0c;然后进行一个可视化的情感分析。想想吧&#xff0c;这个项目…

RPC核心原理

大家好&#xff0c;我是易安&#xff0c;今天我们一起来研究下RPC的核心原理。 什么是RPC&#xff1f; RPC的全称是Remote Procedure Call&#xff0c;即远程过程调用。简单解读字面上的意思&#xff0c;远程肯定是指要跨机器而非本机&#xff0c;所以需要用到网络编程才能实现…

用Gmail邮箱注册任天堂日本区账号

任天堂是一家日本公司&#xff0c;日区的任天堂可以买到常驻的任亏券&#xff0c;兑换任天堂第一方游戏&#xff0c;而且经常搞活动&#xff0c;可以买到低价的游戏。 首先进入任天堂官网 https://accounts.nintendo.com/register 注册账号 比如我的Gmail邮箱为 zhaooleegma…

EBU6304 Software Engineering 知识点总结_3 requirements

requirements 确定需求是软工设计中最重要的部分。 feature to satisfy customer. indicates what should this sys do. 可能是高层抽象的需求 high-level abstract 或者底层具体的 low-level specific. Stakeholder 利益相关者&#xff1a;受系统影响的组织或个人&#x…

STM32驱动W25Q64---笔记

这次来分享最近经常用到的知识点----FLASH 初学者会疑惑&#xff0c;有了EEPROM为什么还要用W25Q64呢&#xff1f;&#xff08;笔者一开始就百思不得其解&#xff09; 答&#xff1a; EEPROM和W25Q64都是用于数据存储的存储器&#xff0c;它们各有优缺点&#xff0c;需要根据…

chatgpt赋能python:Python的修改及其对SEO的影响

Python的修改及其对SEO的影响 介绍 Python是一种高级编程语言&#xff0c;以其简单易学和功能强大而闻名。它被广泛用于开发各种应用程序&#xff0c;从网站到机器学习和大数据分析。Python不断更新和改进&#xff0c;新版本带来了许多新功能和改进&#xff0c;这些修改对SEO…

如何读取带空格的字符串?

scanf()函数在读取字符时&#xff0c;识别到空格就会终止读取&#xff0c;那么如何读取带空格的字符串呢&#xff1f; 一、gets()&#xff08;gets_s()&#xff09; 从标准输入(stdin)&#xff08;指的是键盘输入&#xff09;读取字符&#xff0c;并将它们作为 C 字符串存储到…

1688详情 sign签名分析

本文仅供学习交流&#xff0c;只提供关键思路不会给出完整代码&#xff0c;严禁用于非法用途&#xff0c;若有侵权请联系我删除&#xff01; 网站地址&#xff1a;aHR0cHM6Ly9kZXRhaWwuMTY4OC5jb20vb2ZmZXIvNzEzNDMzMDYyOTUzLmh0bWw 接口&#xff1a;aHR0cHM6Ly9oNWFwaS5tLjE…

软件工程学复习笔记

目录 软件工程学概述软件危机的典型表现、产生原因、消除途径软件的构成&#xff1a;程序、数据、文档软件工程的七点特性软件工程的七条基本原理软件工程方法&#xff1a;传统方法学&#xff0c;面向对象方法学软件的生命周期&#xff1a;三个时期&#xff0c;软件定义&#x…

MMPose学习笔记1

文章目录 摘要什么是人体姿态估计3D 姿态估计人体参数化模型下游任务2D姿态估计多人姿态估计&#xff1a;自顶向下方法基于回归的自顶向下方法基于热力图的自顶向下方法 多人姿态估计&#xff1a;自底向上方法单阶段方法基于Transformer的方法小结 3D姿态估计评估指标 Dense Po…

面向对象特征之一:封装和隐藏

为什么要引入封装性&#xff1f; ●我们程序设计追求“高内聚&#xff0c;低耦合” ➢高内聚:类的内部数据操作细节自己完成&#xff0c;不允许外部干涉; ➢低耦合:仅对外暴露少量的方法用于使用。 ●隐藏对象内部的复杂性&#xff0c;只对外公开简单的接口。便于外界调用&am…

ISIS路由渗透实验

1&#xff09;拓扑 2&#xff09;需求&#xff1a;ISIS全网互联互通 3&#xff09;原因分析&#xff1a; 因为&#xff0c;L1/2 路由器&#xff08;R4、R8&#xff09;学习到L1类型路由信息会装进L2-LSP&#xff0c;在泛洪给其他区域的L2和L1/2路由器&#xff0c;所以&#x…

【socket】从计算机网络基础到socket编程——Windows Linux C语言 + Python实现(TCP+UDP)

一、部分基础知识1.1 计算机网络的体系结构1.11 互联网简介1.12 计算机网络的分类1.13 协议与网络的分层体系结构▶ 协议▶ 网络的分层体系结构 1.14 OSI 七层模型&#xff08;重要&#xff09;▶ OSI 模型的结构▶ OSI 模型各层的功能 1.15 TCP/IP 的体系结构&#xff08;重要…