SpringCloud-服务网关-Gateway

news2024/11/26 0:47:15

1.服务网关在微服务中的应用

(1)对外提供服务的难题分析:
微服务架构下的应用系统体系很庞大,光是需要独立部署的基础组件就有注册中心、配置中心和服务总线、Turbine异常聚合和监控大盘、调用链追踪器和链路聚合,还有Kaka和MQ之类的中间件,再加上拆分后的零散微服务模块。—个小系统都能轻松弄出20个左右的部署包。
如果采用localhost加端口的方式直接访问,如果这些服务—并都要提供给外部用户访问那该怎么办呢?可以让前端程序员加班加点在各个页面给各种不同请求配置URL和端口号,人不是问题,项目完成就行。也可以我们配一个URL,通过F5或者Nginx可以做路由,话是没错,可是这样就要让运维团队手工维护路由规则表,当我们新增删除节点或者因为更换机房导致IP变化的时候就很麻烦。因此我们需要引入—套机制来降低路由表的维护成本。
还有一个问题就是安全性,我们在提供外部服务的时候往往会加入一些访问控制,比如说下单接口不允许未登录用户的访问,有的服务还会通过一些JWT签名等防止客户端篡改数据。如果让每个服务提供者都实现同样的访问验证逻辑未免有些太繁琐,这样纯属是增加研发人员的怒气值,况且如果有一天我们需要更换权限认证方案,比如更换为OAuth2.0,难不成还要每个服务提供者都做变更?
我们如何对外提供服务,既能管好路由规则,还能做好访问控制呢?在这个背景下,API网关应运而生,接待所有来访请求。
(2)网关层
微服务引入一层专事专办的中间层。
两件事:
1.访问控制,看你是否有权限访问,拒绝未授权的来访者
2.引导指路 问清楚你要办的事,指一条明路。找到对应处理这些事的人

网关层引入后,微服务的架构变成:
在这里插入图片描述
网关层作为唯一的对外服务,外部请求不直接访问服务层。由网关层承接所有HTTP
请求,在实际应用中。我们会将Gateway与Nginx一同使用。
(3)访问控制和路由规则
访问控制:
主要包含两个方面的任务,具体的实现并不是由网关层提供的,但是网关作为一个载体承载了两个任务:
拦截请求:有的接口需要登录用户才能访问,对于这类接口的访问,网关层可以检查访问请求中是否携带令牌等身份信息,比兔HTTP Header中的Authorization或者token属性。如果没有携带令牌,说明没登录,可以直接返回403 Forbidden
鉴权:对于携带令牌的服务,我们需要验证令牌的真假,否则用户可以
通过伪造的令牌进行通信,对令牌校验失败的请求,或者令牌已经过期
的请求执行拒绝服务!

路由规则
路由规则包含两个方面,分别是URL映射和服务寻址
URL映射:在大多数情况下,客户端访问的HTTP URL往往不是我们在Controller里配置的真实路径,比如客户端可以发起请求"/password/update"来修改密码,但后台并没有这个服务,这时候就需要网关层做一个路由规则,将来访URL映射成真正的服务路径,比如将刚才的密码修改请求的路径映射到"/user/settings/security/password"请求
服务寻址URL映射:好了之后,网关层就需要找到可以提供服务的服务器地址,对于服务集群的话,还需要实现负载均衡策略。(在Spring Cloud中,Gateway是借助Eureka的服务发现机制来实现服务寻址的,负载均衡则依靠Ribbon)

2.第二代网关组件Gateway介绍

Gateway业务场景:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.Gateway体系架构解析

(打开Gateway的自动装配工厂,gatewayAutoConfiguration看,第一个就是Netty)

Netty是什么?在网络传输领域Netty就是身份的象征,它是非阻塞、高性能、高可靠的异步输入输出框架,用一个字概括就是"快"。这里我们不对Netty做深入探讨,但是需要了解下Netty在Gateway中主要应用在以下几个地方:
发起服务调用:由NettyRoutingFilter过滤器实现,底层采用基于Netty的HttpClient发起外部服务的调用
Response传输:由NettyResponseFilter过滤器实现,网络请求结束后要将Response回传给调用者

  • Socket连接:具体由ReactortNettyWebSocketClient类承接,通过Netty的Httpclient发起连接请求
    在Gateway中发起Request和回传Response之类的步骤都是通过一系列过滤翮完成的,有关过滤器的内容将在稍后介绍。

(正常HTTP调用与netty的http调用的区别:
核心区别:javax.servlet.http.HttpServletRequest主要用于服务器端的HTTP请求处理,而Netty的HttpClient用于客户端发起HTTP请求)

在这里插入图片描述
Client发起请求到服务网关之后,由NettyRoutingFilter底层的HttpClient(Netty组件)向
服务发起调用,调用结束后,Response有NettyResponseFilter再回传给客户端。有了netty加持,网络请求效率大幅提升!Netty贯穿从Request发起到Response结束的过程,承担了所有网络调用相关的任务

(1)Gateway自动装配:
在这里插入图片描述
AutoConfig: 作为核心自动装配主类,GatewayAutoConfiguration负责初始化所有的Route路由规则、Predicate断言工厂和Filter(包括Global Filter和Route Filter),这三样是Gateway吃饭的家伙,用来完成路由功能。AutoConfig也会同时加载Netty配置
LoadBalancerGlient: 这部分在AutoConfig完成之后由GatewayLoadBalancerClientAutoConfiguration负责加载,用来加载Ribbon和一系列负载均衡配置
ClassPathWarning:同样也是在AutoConfig完成之后触发(具体加载类为GatewayClassPathWarningAutoConfiguration),由于Gateway底层依赖Spring WebFlux的实现,所以它会检查项目是否加载了正确配置
Redis:在Gateway中Redis主要负责限流的功能。
除了上面几个核心装配工厂以外,还有两个打酱油的路人,它们并不直接参与Gateway的核心功能,但是会提供—些重要的支持功能:
GatewayMetricsAutoConfiguration:负责做一些统计工作,比如对所谓的“short task"运行时长和调用次数做统计
GatewayDiscoveryClientAutoConfiguration:服务发现客户端自动装配类

爬坑指南
Gateway项目启动出错,但是查来查去,发现也没有什么配置问题。这时候就要看一下是不是引入了错误的依赖,Gateway比较坑的一个地方是它基于WebFlux实现,因此它需要的依赖是spring-boot-starter-webflux,假如我们不小心引入了spring-boot-starter-web将导致启动问题,
由于我们大部分的Spring Cloud项目都依赖spring-boot-starter-web,所以很容易就误将其依赖导入到了Gateway项目中,碰到这种问题只要打印出依赖树,排查下错误依赖的来源,然后将它在pom中排除出去就好了。
路由流程
这里就涉及到了Gateway最核心的路由功能,路由主要由断言和过滤器配合来实现,我们把这部分内容拆分为3个小节,分别介绍路由的整体功能、断言的使用、过滤器原理和生命周期。

4.路由功能详解

Gateway网关的路由功能可不简简单单的转发请求,在请求到达网关再流转到指定服务之间发生了很多事!它不光可以拒绝请求,甚至可以篡改请求的参数!

一个route包含完整转发规则的路由,主要由一下三部分组成:

在这里插入图片描述
断言集合:断言是路由处理的第一个环节,它是路由的匹配规则,它决定了一个网络请求是否可以匹配给当前路由来处理。之所以它是一个集合的原因是我们可以给一个路由添加多个断言,当每个断言都匹配成功以后才算过了路由的第一关。有关断言的详细内容将在下一小节进行介绍
过滤器集合:如果请求通过了前面的断言匹配,那就表示它被当前路由正式接手了,接下来这个请求就要经过一系列的过滤器集合。过滤器的功能就是八仙过海各显神通了,可以对当前请求做一系列的操作,比如说权限验证,或者将其他非业务性校验的规则提到网关过滤器这一层。在过滤器这一层依然可以通过修改Response里的status Code达到中断效果,比如对鉴权失败的访问请求设置Status Code为403之后中断操作。有关过滤器的详细内容将在后面的小节介绍
URI:如果请求顺利通过过滤器的处理,接下来就到了最后一步,那就是转发请求。URI是统一资源标识符,它可以是一个具体的网址,也可以是IP+端口的组合,或者是Eureka中注册的服务名称

关于负载均衡:
对最后一步寻址来说,如果采用基于Eureka的服务发现机制,那么在Gateway的转发过程中可以采用服务注册名的方式来调用,后台会借助Ribbon实现负载均衡(可以为某个服务指定具体的负载均衡策略),其配置方式如:1b://FEIGN-SERVICE-PROVIDER/。前面的lb就是指代Ribbon作为LoadBalancer,

路由的规则流程:
在这里插入图片描述
Predicate Handler:具体承接类是RoutePredicateHandlerMapping。首先它获取所有的路由(配置的routes全集),然后依次循环每个Route,把应用请求与Route中配置的所有断言进行匹配,如果当前Route所有断言都验证通过,Predict Handler就选定当前的路由。这个模式是典型的职责链。
Filter Handler:在前一步选中路由后,由FilteringWebHandler将请求交给过滤器,在具体处理过程中,不仅当前Route中定义的过滤器会生效,我们在项目中添加的全局过滤器(Global Filter)也会一同参与。同学们看到图中有Pre Filter和Post Filter,这是指过滤器的作用阶段,我们在稍后的章节中再深入了解
寻址:这一步将把请求转发到URI指定的地址,在发送请求之前,所有Pre类型过滤器都将被执行,而Post过滤器会在调用请求返回之后起作用。

5.断言功能详解(Predict)

Predicate机制:
Predicate是Java 8中引入的一个新功能,就和我们平时在项目中写单元测试时用到的Assertion差不多,Predicate接收一个判断条件,返回一个ture或false的布尔值结果,告知调用方判断结果。你也可以通过and (与),or(或)和negative (非)三个操作符将多个Predicate串联在一块共同判断。

如果Gateway是挡在微服务前面的中介,那这个Predicate就是和中介的接头暗号。比如中介可以要求你的Request中必须带有某个指定的参数叫name,对应的值必须是一个指定的信息,如果你的Request中没有包含指定信息,或者指定信息错误,那就是断言失败。只有当你的请求完全和接头暗号匹配的时候,中介才能给你放行。

说白了predicate就是一种路由规则,通过gateway中丰富内置断言的组合,
我们就能让一个请求找到对应的route来处理。

断言的作用阶段:
在一个请求抵达网关层后,首先就要进行断言匹配,在满足所有断言之后
才会进入Filter阶段!

常用断言介绍:gateway提供了十多种内置断言:
路径匹配:path断言是最常用一个断言。
.route(r -> r.path(“/gateway/**”)
.uri(“lb://FEIGN-SERVICE-PROVIDER/”)
)
.route(r -> r.path(“/baidu”)
.uri(“http://baidu.com:80/”)
)
Path断言的使用非常简单,就像我们在Controller中配置@RequestPath的方式一样,在Path断言中填上—段URL匹配规则,当实际请求的URL和断言中的规则相匹配的时候,就下发到该路由中URI指定的地址,这个地址可以是一个具体的HTTP地址,也可以是Eureka中注册的服务名称。在上面的例子中,如果我们访问"Igateway/test”,这个路径将匹配到第一个路由。

Method断言:
这个断言是专门验证HTTP Method的,在下面的例子中,我们把Method断言和Path断言通过一个and连接符合并起来,共同作用于路由判断,当我们访问"lgateway/sample"并且HTTP Method是GET的时候,将适配下面的路由
.route(r -> r.path(“/gateway/“)
.and().method(HttpMethod.GET)
.uri(“lb://FEIGN-SERVICE-PROVIDER/”)
)
RequestParam匹配:请求断言也是业务中经常使用的,它会从ServerHttpRequest中
的Parameters列表中查询指定的属性,如下有两种不同的使用方式:

.route(r -> r.path(”/gateway/
”)
.and().method(HttpMethod.GET)
.and().query(“name”, “test”)
.and().query(“age”)
.uri(“lb://FEIGN-SERVICE-PROVIDER/”)
)
属性名验证:如query(“age”),此时断言只会验证QueryPrameters列表中是否包含了一个叫age的属性,并不会验证它的值
属性值验证:如query ( "“name” ,“test”),它不仅会验证name属性是否存在,还会验证它的值是不是和断言相匹配,比如当前的断言会验证请求参数中的name属性值是不是test,第二个参数实际上是一个用作模式匹配的正则表达式

**Header断言:这个断言会检查Header中是否包含了响应的属性,通常可以用来
验证请求是否携带了令牌:
.route(r -> r.path("/gateway/
")
.and().header(“Authorization”)
.uri(“lb://FEIGN-SERVICE-PROVIDER/”)
)
上面的断言指定Header中必须包含一个Authorization属性,Header断言和Query断言
一样,也可以通过传入两个参数形式对属性值进行检查

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

.route(r -> r.path(“/gateway/**”)
.and().cookie(“name”, “test”)
.uri(“lb://FEIGN-SERVICE-PROVIDER/”)
)

时间片匹配:
时间匹配有三种模式,分别是Before、After和Between,这些断言指定了在什么时间范围内路由才会生效
.route(r -> r.path(“/gateway/**”)
.and().before(ZonedDateTime.now().plusMinutes(1))
.uri(“lb://FEIGN-SERVICE-PROVIDER/”)
)

自定义断言:
Gateway也提供了一个扩展方法,用来将自定义的断言应用到路由上。老师给出两点提示,希望同学们顺着这个方向来参考Gateway的源码,实现一个自定义断言,完成一个小功能:将所有请求参数大于5个的访问请求拦截掉,即RequestParam个数小于5个的请求才能被放行。
提示1:所有断言类都可以继承自AbstractRoutePredicateFactory
提示2:在路由配置时可以通过predicate或者asyncPredicate传入一个自定义断言

6.过滤器原理和生命周期

过滤器的工作模式:
Gateway的过滤器是一样的模型,他们经过优先级排序,所有网关调用请求从最高优先级的过滤器开始,一路走到头,直到被最后一个过滤器处理。

过滤器的实现方式:
在Gateway实现一个过滤器非常简单,只要实现GatewayFilter接口的默认方法就好!

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    // 随意发挥
    return chain.filter(exchange);    
}

这里面有两个关键信息:
ServerWebExchange:这是Spring封装的HTTP request-response交互协议,从中我们可以获取request和response中的各种请求参数,也可以向其中添加内容
GatewayFilterChain:它是过滤器的调用链,在方法结束的时候我们需要将exchange对象传入调用链中的下一个对象

过滤器的执行阶段:
不同于springcloud中上一代网关组件Zuul里对过滤器的Pre和Post的定义,
Gateway是通过Filter中的代码来实现类似Pre和Post的效果!
Pre和Post是指当代过滤器执行阶段,Pre是在下一个过滤器之前被执行,Post
是在过滤器执行过后再执行。我们在GatewayFileter也可以同时定义Pre和Post执行逻辑!!

Pre类型:
AddResponseHeaderGatewayFilterFactory,它可以向Response中添加Header信息:

@Override
public GatewayFilter apply(NameValueConfig config) {
	return (exchange, chain) -> {
        exchange.getResponse().getHeaders().add(config.getName(), config.getValue());
        return chain.filter(exchange);
    };
}

Post类型:
SetStatusGatewayFilterFactory,它在过滤器执行完毕之后,将制定的HTTP status返回给调用方!!

return chain.filter(exchange).then(Mono.fromRunnable(() -> {
		// 这里是业务逻辑
		}));   

这个过滤器的主要逻辑在then方法中,then是一个回调函数,在下级调用链路都完成以后再执行,因此这类过滤器可以看做是Post Filter

过滤器排座次:
在Gateway中我们可以通过实现org.springframework.core.Ordered接口,来给过滤器指定执行顺序,比如下面的代码实现了Ordered接口方法,将过滤器执行顺序设置为0:

@Override
public int getOrder() {
	return 0;
}                                                          
Pre

类型的过滤器来说,数字越大表示优先级越高,也就越早被执行。但对于Post类型的过滤器,则是数字越小越先被执行。

过滤器示例:
Header过滤器
这个系列有很多组过滤器,AddRequestHeader和AddResponseHeader,分别向Request和Response里加入指定Header。相应的RemoveRequestHeader和RemoveResponseHeader分别做移除操作,用法也很简单:

.filters(f -> f.addResponseHeader("who", "gateway-header"))
                                             

上面的例子会向header中添加一个who的属性,对应的值是gateway-heade

StringPrefix过滤器:
这是个比较常用的过滤器,它的作用是去掉部分URL路径。比如我们的过滤器配置如下:

.route(r -> r.path("/gateway-test/**")
             .filters(f -> f.stripPrefix(1))
             .uri("lb://FEIGN-SERVICE-PROVIDER/")
)        

假如HTTP请求访问的是/gateway-test/sample/update,如果没有StripPrefix过滤器,那么转发到FEIGN-SERVICE-PROVIDER服务的访问路径也是一样的。当我们添加了这个过滤器之后,Gateway就会根据“stripPrefix(1)”中的值截取URL中的路径,比如这里我们设置的是1,那么就去掉一个前缀,最终发送给后台服务的路径变成了“/sample/update”

PrefixPath过滤器:
它和StripPrefix的作用是完全相反的,会在请求路径的前面加入前缀

.route(r -> r.path("/gateway-test/**")
             .filters(f -> f.prefixPath("go"))
             .uri("lb://FEIGN-SERVICE-PROVIDER/")
)      

比如说我们访问“/gateway-test/sample”的时候,上面例子中配置的过滤器就会把请求发送到“/go/gateway-test/sample”。

RedirectTo过滤器:
可以把收到特定的状态码的请求重定向到一个特定的网址:
.filters(f -> f.redirect(302, “https://www.xxx.com/”))
上面的例子接收HTTP status code和URL两个参数,如果请求结果是404,则重定向到第二个参数指定的页面,这个功能也可以做统一异常处理,将Unauthorized或Forbidden请求重定向到登录页面。

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

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

相关文章

macOS使用Karabiner-Elements解决罗技鼠标G304连击、单击变双击的故障

记录一下罗技鼠标G304单击变双击的软件解决过程和方案&#xff08;适用于macOS&#xff0c; 如果是Windows&#xff0c;使用AutoHotKey也有类似解决办法、方案&#xff0c;改日提供&#xff09;&#xff1a; 背景&#xff1a;通过罗技Logitect G HUB软件对罗技的游戏鼠标侧键b…

TikTok美区日销二十万美金爆款黑马!胸贴赛道成功起飞!

从去年开始&#xff0c;一项名为“No bra”&#xff08;无胸罩&#xff09;的挑战就长期刷屏TikTok。随着平台内各大博主和明星站台发声&#xff0c;越来越多用户也参与其中&#xff0c;话题的热度逐渐走向高潮。截止到目前&#xff0c; TikTok上相关话题累计播放量已高达8.3亿…

数据恢复篇:5 款最佳 Mac 数据恢复软件

说到保护我们的数字生活&#xff0c;数据恢复软件的重要性怎么强调都不为过。无论您是意外删除了假期照片的普通用户&#xff0c;还是面临硬盘损坏的专业人士&#xff0c;随之而来的恐慌都是普遍存在的。幸运的是&#xff0c;数据恢复工具可以缓解这些压力。在Mac用户可用的众多…

Postman接口测试工具详解【保姆级教程】

大家好,我是CodeQi! 在我们日常的开发工作中,无论是前端还是后端,API 接口的测试都是必不可少的一环。 你有没有遇到过这样的情况:接口测试工具复杂难用,使用起来让人抓狂;或者手动构造请求效率低下,容易出错? 别担心,我今天要介绍的 Postman 工具,将会彻底改变你…

【实用小工具】Aconvert文件转换神器

1 Aconvert简介 Aconvert.com在线转换各类PDF&#xff0c;文档&#xff0c;电子锁&#xff0c;图像&#xff0c;图标&#xff0c;视频&#xff0c;音频和压缩文件。域名中的“A”代表“ALL”。您可以点击右上角的转换按钮开始快速转换&#xff1a;无需进入目录&#xff0c;直接…

visual studio远程调试

场景一&#xff08;被远程调试的电脑&#xff09; 确定系统位数 我这里是x64的 找到msvsmon.exe msvsmon.exe目录位置解释&#xff1a; “F:\App\VisualStudio\an\Common7\IDE\”是visual studio所在位置、 “Remote Debugger\”是固定位置、 “x64”是系统位数。 拼起来就是…

【Linux】正确的关机方法

1. Linux正确的关机方式 如何关机呢&#xff1f;我想&#xff0c;很多朋友在DOS年代已经有在玩计算机了。在当时我们关闭DOS的系统时&#xff0c;常常是直接关闭电源开关&#xff0c;而Windows 在你不爽的时候&#xff0c;按着电源开关四秒也可以关机&#xff0c;但是在Linux则…

每日一题——Python实现PAT乙级1026 程序运行时间(举一反三+思想解读+逐步优化)五千字好文

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 代码结构和逻辑 时间复杂度 空间复杂度 代码优化建议 总结 我要更强 …

C基础-标准库上

目录 零. 简介 一. assert 二. ctype 三. errno 四. float 五. limits 六. locale C基础-标准库下连接: http://t.csdnimg.cn/LCcXR 零. 简介 C 语言标准库是一组由 ANSI C 标准规定的头文件和函数的集合&#xff0c;为 C 语言提供了常用的功能&#xff0c;以满足各种基…

晨持绪科技:抖音店铺运营思路

在抖音这个充满活力与创意的平台上&#xff0c;店铺运营不仅仅是一种商业行为&#xff0c;它更是一种艺术的展示。如同画家在画布上勾勒出色彩斑斓的画面&#xff0c;抖音店铺的运营者们也在平台上精心策划着每一个细节&#xff0c;以吸引更多的目光和流量。 内容创作。内容是吸…

注意!!2024《信息系统运行管理员》易混淆知识点来了,赶紧收藏

宝子们&#xff0c;在复习信息系统运行管理员中&#xff0c;是不是觉得有很多知识点含义比较相近&#xff0c;很多友友刚看的时候估计会像我一样迷迷糊糊的&#xff0c;作为一个软考老鸟&#xff0c;在这里给大家整理了信息系统运行管理员学习过程中易混淆的知识点&#xff0c;…

瑞数信息:智能防护新时代,看AI如何筑起网络防线

AI时代&#xff0c;网络安全危与机并行。 尤其是近年来大火的大模型&#xff0c;对于网络安全行业的影响与其他行业有所不同&#xff0c;一方面&#xff0c;AI能够通过大幅降低了安全攻击的门槛&#xff0c;网络威胁的复杂性和多样性不断增加&#xff0c;如自动化攻击、零日漏…

AWS亚马逊云服务器:强大的云计算服务

AWS亚马逊云服务器&#xff08;Amazon Web Services&#xff0c;简称AWS&#xff09;是亚马逊公司推出的一项云计算服务。作为全球领先的云计算服务提供商&#xff0c;AWS为个人、企业提供了稳定、可靠且安全的云计算服务。AWS亚马逊云服务器的出现&#xff0c;极大地改变了传统…

SALOME源码分析:View Model

作为一款开源的CAx(CAD/CAE/CAM)软件集成平台&#xff0c;为了实现各个Module支持不同的数据显示与交互方案&#xff0c;出于扩展性的考虑&#xff0c;SALOME引入了View Model&#xff0c;用以支持OpenGL、OCC、VTK、ParaView、Qwt等数据显示与交互实现。 本文将以OCCViewer、…

电气-伺服(3)伺服选型计算

一、直线运动&#xff1a; 转矩&#xff1a; 二、 旋转运动 线速度和角速度的关系&#xff1a; 三、伺服选型 原则 选型计算步骤 1、转矩计算 常见物体惯量计算&#xff1a; 常见传动机构转动惯量的计算 直接驱动&#xff1a; 案例&#xff1a; 同步带传动&#xff1a; 丝杆…

新加坡博士申请|中国社科院-新加坡社科大学联合培养工商管理博士

新加坡博士申请|中国社科院-新加坡社科大学联合培养工商管理博士 【项目名称】中国社会科学院大学与新加坡新跃社科大学工商管理博士项目 【学制】最短3年&#xff0c;最长不超过7年 【学位证书】新加坡新跃社科大学工商管理博士学位 【招生对象】企业高管、咨询顾问及其他有…

雨量监测站的工作内容是什么?

在现代气象观测体系中&#xff0c;雨量监测站扮演着至关重要的角色。它们不仅为我们提供了关于降水量的关键数据&#xff0c;还帮助我们更好地理解气候模式&#xff0c;预测自然灾害&#xff0c;并优化水资源管理。本文将探讨雨量监测站的工作内容&#xff0c;以及它在气象观测…

Vue + Element UI + JSEncrypt实现简单登录页面

安装依赖 npm install jsencrypt --save局部引入 import JSEncrypt from jsencrypt/bin/jsencrypt;登录页面index.vue <template><div class"loginbody"><div class"logindata"><div class"logintext"><h2>Wel…

《梦醒蝶飞:释放Excel函数与公式的力量》8.3 COUNTBLANK函数

8.3 COUNTBLANK函数 在数据处理和分析中&#xff0c;我们经常需要识别和统计数据集中的空白单元格。COUNTBLANK函数是Excel中用于统计某个范围内空白单元格数量的强大工具。 8.3.1 函数简介 COUNTBLANK函数用于统计指定范围内的空白单元格数量。这在数据清洗、数据完整性检查…

《NATURE丨使用 AlphaFold 3 准确预测生物分子相互作用的结构》

NATURE丨使用 AlphaFold 3 准确预测生物分子相互作用的结构 注意&#xff01;&#xff1a;本文创作仅根据个人理解和网络信息&#xff0c;如有错误恳请指正&#xff01;谢谢&#xff01; 大家好&#xff0c;今天分享的文献是2024年5月发表在Nature上的“ Accurate structure …