【Nginx34】Nginx学习:安全链接、范围分片以及请求分流模块

news2024/11/16 3:49:11

Nginx学习:安全链接、范围分片以及请求分流模块

又迎来新的模块了,今天的内容不多,但我们都进行了详细的测试,所以可能看起来会多一点哦。这三个模块之前也从来都没用过,但是通过学习之后发现,貌似还都挺有用。当然,还是要根据具体业务情况来看,如果你的业务中有用到,那么就可以尝试一下哦。

安全链接是实现请求 URL 的验证模块,通过签名密钥来判断请求是否可以返回相应的数据。范围分片一般用于分段下载,主要用于代理时请求后端的 Range 头的设置。最后的请求分流不太好说清楚,咱们到文章中详细再说明吧。

今天的内容大部分可以在 http、server、location 下配置,仅有两个只能在 http 或 location 下配置,我会单独说。

安全链接

安全链接模块 ngx_http_secure_link_module(0.7.18),可以用于检查请求链接的真实性,保护资源免受未经授权的访问,并限制链接寿命。

请求链接的真实性通过将请求中传递的校验和值与为请求计算的值进行比较来验证。这个其实就像我们做 App 接口时,一般都会加个 sign 签名一样,客户端使用和服务端相同的方式进行签名,用于验证客户端发来的请求是否有效。另外,这个模块还可以根据链接的生命周期来进行验证,如果生命周期有限且时间已过,则认为该链接已过期。这些检查的状态在 $secure_link 变量中可用。

该模块提供了两种可选的操作模式。第一种模式由secure_link_secret 指令启用,用于检查请求链接的真实性以及保护资源免受未经授权的访问。第二种模式 (0.8.50) 由secure_link 和secure_link_md5 指令启用,也用于限制链接的生命周期。这两种形式我们后面都会进行测试。

它不包含在 Nginx 核心源码中,需要通过 --with-http_secure_link_module 编译安装。我们还是先来看看这个模块所包含的配置项,然后再进行综合的测试。

secure_link

定义一个带有变量的字符串,将从中提取链接的校验和值(md5+base64)和生命周期。

secure_link expression;

表达式中使用的变量通常与请求相关联,一般可以设置为 $arg_md5 ,这个变量名是可以自己起的,目的就是获取到这个加密值。将从字符串中提取的校验和值与 secure_link_md5 指令定义的表达式的 MD5 哈希值进行比较。如果校验和不同,则 $secure_link 变量设置为空字符串。如果校验和相同,则检查链路寿命。

如果链接的生命周期有限且时间已过,则 $secure_link 变量设置为“0”。否则,设置为“1”。请求中传递的 MD5 哈希值以 base64url 编码。如果链接的生命周期有限,则过期时间设置为自 Epoch(1970 年 1 月 1 日星期四 00:00:00 GMT)以来的秒数。

该值在 MD5 哈希后的表达式中指定,并以逗号分隔,比如 $arg_sign$arg_expires ,后面这个 expires 就是可以通过 GET 获取的过期时间值。请求中传递的过期时间可通过 $secure_link_expires 变量在secure_link_md5 指令中使用,不使用也行,后面测试时我们会看到。如果未指定过期时间,则链接具有无限的生命周期。

secure_link_md5

定义一个表达式,将计算 MD5 哈希值并将其与请求中传递的值进行比较。

secure_link_md5 expression;

表达式应包含链接(资源)的安全部分和秘密成分。如果链接的生命周期有限,则表达式还应包含 $secure_link_expires 。为了防止未经授权的访问,表达式可能包含有关客户端的一些信息,例如其地址和浏览器版本。

比如我们可以指定为 secure_link_md5 '$uri zzyy'; ,那么上面 secure_link 第一个设置的值就是 base64_encode(md5('请求的链接地址 zzyy')) 这样的结果就可以和 secure_link_md5 的值匹配上。如果不匹配,$secure_link 会是空,如果使用了过期时间,并且时间确实过期了,那么就是 0 ,这时就可以使用 if 指令判断是否验证成功做出不同的操作。

看不懂是吧?没事,一会测试例子运行一下就明白了。

secure_link_secret

定义用于检查所请求链接的真实性的秘钥。

secure_link_secret word;

仅能在 location 下配置。请求链接的完整 URI 如下所示:

/prefix/hash/link

其中 hash 是 MD5 散列的十六进制表示,用于连接链接和秘钥,prefix 是不带斜杠的任意字符串。如果请求的链接通过了真实性检查,则 $secure_link 变量设置为从请求 URI 中提取的链接。否则,$secure_link 变量设置为空字符串。

这个又是啥玩意?注意,它是单独使用的,和上面那两个没关系。假如我们设置 secure_link_secret zyblog; 请求地址为 /p/17ceb6c14933609f0ab68e37fe633b1a/1.html ,那么中间加密的部分其实就是 md5('1.htmlzyblog') 。前面的 /p/ 是没啥用的,因为这个配置只能在 location 下配置,所以这个前缀就是 location 的 URI 部分。

使用上面的链接可以将 $secure_link 设置为 1.html ,然后我们就可以通过 rewrite 去请求真实的 1.html 了,这里可以加个判断,如果 $secure_link 为空,就返回异常页面,这样就实现了链接的验证。

嗯,说不明白,还是一会看测试效果吧。

变量

  • $secure_link 链接检查的状态。具体值取决于所选的操作模式

  • $secure_link_expires 请求中传递的链接的生命周期,仅用于 secure_link_md5 指令

安全链接测试(一)secure_link 与 secure_link_md5

好了,看完了配置指令,咱们就来看看怎么使用。首先看第一种方式,就是 secure_link 与 secure_link_md5 组合的方式。先添加以下的测试代码。

log_format securelink 'secure_link_expires=$secure_link_expires, secure_link=$secure_link';

server{
  listen 8034;

  location /securelink1/ {
    access_log logs/34.securelink.log securelink;
    alias html/;

    secure_link $arg_md5,$arg_expires;
    secure_link_md5 "$secure_link_expires$uri$remote_addr zyblog secret";

    if ($secure_link = "") {
      return 200 nosecure;
    }
    if ($secure_link = "0") {
      return 200 timeexpire;
    }
  }

}

上面的日志记录,是为了看两个变量的变化情况。然后我们指定 secure_link 的值,分别是从 GET 获取到的 md5 参数和 expires 参数。expires 可以给个时间戳,我们给的是明天的一个时间点。secure_link_md5 我们设置的内容是通过 "过期时间+请求链接URI+IP地址+空格+zyblog+空格+secret" 这一个字符串进行加密的。

然后就是使用两个 if 指令进行判断,如果 secure_link 为空,表示安全验证没通过,如果 $secure_link 是 0 ,表示过期了,分别通过 return 返回不同的内容。

然后咱们先测试一下啥参数都不带的。

➜  ~ curl 'http://192.168.56.88:8034/securelink1/'
nosecure

直接返回 nosecure 。再看下日志。

// 34.securelink.log
secure_link_expires=-, secure_link=-

两个变量都是空的。然后我们准备一下要加密的签名数据,根据 secure_link_md5 的设置,我们可以直接通过 Linux 的 openssl 工具进行加密,如果没有安装这个的话可以自己安装一下哦,或者使用 PHP 以及其它动态语言也是可以的,就是md5 之后再 base64 一下。

[root@localhost article.http.d]# echo -n '1663719873/securelink1/192.168.56.1 zyblog secret' | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =
VEJ41JfqBbXXaGJRXWK3rw

1663719873 是我们一会要通过 expires 参数传过来的过期时间,现在用当前时间,后面我们才会测试过期的问题,在 secure_link 配置中逗号后面第二个参数我们放置的就是它,然后它就会到 $secure_link_expires 变量中。secure_link_md5 中第一个变量就是它,所以我们要拼接在最前面,然后是请求的地址,这里就是请求根目录,URI 就是 /securelink1/ ,然后就是客户端 IP 地址,我这里是 192.168.56.1,最后接上空格和固定的字符串,加密后的结果就是 VEJ41JfqBbXXaGJRXWK3rw 。然后发送请求时使用 GET 带上这两个参数吧。

curl 'http://192.168.56.88:8034/securelink1/?md5=VEJ41JfqBbXXaGJRXWK3rw&expires=1663719873'

是不是发现可以打开首页了?因为我们做了 alias ,所以就是直接打开 html 目录下的首页了。再看下日志。

// 34.securelink.log
secure_link_expires=1663719873, secure_link=1

两个值都取到了,secure_link 的值是 1 ,不符合 if 每个人的中的内容,不会直接 return 返回,正常向下执行。

secure_link_expires=1662769473, secure_link=1

接下来试试过期问题,先改造一下。

secure_link $arg_md5,1662769473;
secure_link_md5 "$uri$remote_addr zyblog secret";

这回我们让过期时间的设置不使用传递过来的参数了,而是一个固定值,这个值是比现在的时间稍微早一点的时间。然后 secure_link_md5 也改了下,不使用 secure_link_expires

➜  ~ curl 'http://192.168.56.88:8034/securelink1/?md5=EzLUxfpwyLdp7bDv0m0l0Q'
timeexpire

查看日志,secure_link 被设置成了 0 ,而 secure_link_expires 则是我们 secure_link 中设置的那个值。

// 34.securelink.log
secure_link_expires=1662769473, secure_link=0

然后我们再将过期时间设置为比现在晚一点的时候,比如比当前时间多个几分钟。

secure_link $arg_md5,1663644527;

现在访问又正常了,从这里可以看出,过期时间是基于当前系统的时间值的,如果小于当前系统时间,就是过期的,如果大于当前系统时间,就是正常的。而如果将 $secure_link_expires 加入到 secure_link_md5 中一起加密的话,则是保证这个请求必须在 1 秒内到达。假设有代理或者黑客大佬中间拦截了请求,就会导致时间过期,而如果时间参数对不上加密内容,则会导致验证不通过。这里和我们之前讲过的接口签名 sign 是一样的概念。

时间参数最重要的作用,就是让签名产生变化,如果没有这个动态值,那么签名就会一直是一样的,这种签名有跟没有不就没啥区别了。

不过就像做接口签名一样,客户端和服务端如果时间不一致,就可能导致签名失败。一般有两种解决方式,一是对发来的时间参数判断,比如1分钟或几分钟内的都有效,二是每次接口请求都返回服务器的时间,让客户端保存一份,并以这个时间戳为基准进行计时。通常来说,第一种方式是我们用动态语言时常用的方式,第二种则可以应用在 Nginx 这个配置中。

对于接口签名不太了解的同学,可以查阅下相关的资料哦。一般都是通过 URI+请求参数排序+时间戳 这种加密形式进行接口签名的。

当然,我们也可以不使用过期时间,secure_link 不加过期时间参数就可以了。

secure_link $arg_md5;
secure_link_md5 "$uri$remote_addr zyblog secret";

然后对参数进行加密。

[root@localhost article.http.d]# echo -n '/securelink1/192.168.56.1 zyblog secret' | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =
EzLUxfpwyLdp7bDv0m0l0Q

直接访问,可以正确获得访问结果。

curl 'http://192.168.56.88:8034/securelink1/?md5=EzLUxfpwyLdp7bDv0m0l0Q'

日志的内容如下。

secure_link_expires=-, secure_link=1

安全链接测试(二)secure_link_secret

第二种,secure_link_secret 的使用方法,还是先来准备测试代码吧。

location /securelink2/ {
  access_log logs/34.securelink.log securelink;
  alias html/;
  
  secure_link_secret zyblog.com.cn;
  if ($secure_link = "") {
    return 200 nosecure;
  }

  rewrite ^ /$secure_link;
}
location / {
  root html;
}

这段代码中,我们指定签名的 Key 是 zyblog.com.cn 。如果匹配不成功,就返回 nosecure 的内容,如果成功了,$secure_link 会变成签名内容之后的 URI 地址。也就是上面配置解释中 link 的部分。接着就通过 rewrite 重写到 link 地址。

先来看看直接访问的效果。

curl 'http://192.168.56.88:8034/securelink2/aaa'
nosecure

不出意外的返回 nosecure ,因为我们的验证没有通过,$secure_link 的值是空的,先做一个加密密钥过来吧,根据规则,直接拼接 aaa 和 zyblog.com.cn ,然后 md5 就可以了,这里不需要再 base64 了。

[root@localhost article.http.d]# echo -n 'aaazyblog.com.cn' | openssl md5 -hex
(stdin)= e09475846aa906796ef997b684eced07

获得密钥之后,加到 location 和 aaa 中间。

curl 'http://192.168.56.88:8034/securelink2/e09475846aa906796ef997b684eced07/aaa'

是不是可以正常访问啦,看看日志内容。

// 34.securelink.log
secure_link_expires=-, secure_link=aaa

secure_link 确实变成了密码后面的 URI 内容了。对于指定的文件也需要加密。

[root@localhost article.http.d]# echo -n 'tf2/2.htmlzyblog.com.cn' | openssl md5 -hex
(stdin)= 2fef203746d3684862e8d2607bfebc86

现在需要访问的是 tf2 目录下的 2.html 文件。

curl 'http://192.168.56.88:8034/securelink2/2fef203746d3684862e8d2607bfebc86/tf2/2.html'

也是可以正常访问的。这里需要注意的是,它仅能对非根的的路径进行安全连接保护。比如下面这样就不行。

curl 'http://192.168.56.88:8034/securelink2/xxxx/'

即使你是 "zyblog.com.cn" 或 “/zyblog.com.cn” 这样加密都不行,但要想直接访问可以直接指定文件名。

[root@localhost article.http.d]# echo -n 'index.htmlzyblog.com.cn' | openssl md5 -hex
(stdin)= 2a19ca1a01c0121c7bb6b4ecb8d109dc

这样就可以访问根目录下的 index.html 了。

curl 'http://192.168.56.88:8034/securelink2/2a19ca1a01c0121c7bb6b4ecb8d109dc/index.html'

范围分片

这里的范围分片,其实就是范围请求的意思,也就是 HTTP 中的那个 Range 请求头和响应头的作用。不过这里的配置不是针对客户端的,而是针对代理服务器的。它的命名是 ngx_http_slice_module 模块(1.9.8),是一个过滤器,用于将请求拆分为子请求,每个子请求返回一定范围的响应。过滤器提供更有效的大响应缓存。

它只有一个配置指令,并且不是包含在 Nginx 核心源码中的,需要通过 --with-http_slice_module 编译。

slice

设置切片的大小。

slice size;

默认 0 表示禁用将响应拆分为切片。请注意,过低的值可能会导致内存使用过多并打开大量文件。

为了让子请求返回所需的范围,应将 $slice_range 变量作为 Range 请求标头字段传递给代理服务器。如果启用了缓存,则应将 $slice_range 添加到缓存键中,并应启用具有 206 状态代码的响应的缓存。

变量

  • $slice_range HTTP字节范围格式的当前切片范围,例如bytes=0-1048575。

范围分片测试

这个测试需要借助反向代理,因为它主要是针对代理的子请求的嘛。所以我们添加如下配置。

# http
proxy_cache_path slicecache levels=1:2 keys_zone=slicecache:10m;

server{
  ………………
  location ~ /slice(.*) {
    slice             100;
    proxy_cache       slicecache;
    proxy_cache_key   $uri$is_args$args$slice_range;
    proxy_set_header  Range $slice_range;
    proxy_cache_valid 200 206 10m;
    proxy_pass        http://127.0.0.1/$1?$args;
  }
}

代理相关的配置就不多说了,主要就是做了个代理缓存。然后添加了 slice 指令,设置为 100 个字符。然后需要设置代理请求头的 Range 头,值直接就放 $slice_range 就好了。另外就是有效缓存响应码要把 206 加上。这些配置都是我们之前在学习代理时讲过的。

然后准备一个 PHP 文件,没什么特别的内容,就是获取 Range 请求头的内容,然后返回响应时响应为 206 状态码,并且添加 Content-Range 响应头。最后循环随机输出数据。

// vim /usr/local/nginx/html/fastcgi1/slice/1.php
if (isset ( $_SERVER ['HTTP_RANGE'] )) {
  if (preg_match ( '/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER ['HTTP_RANGE'], $matches )) {
    $begin = intval ( $matches [1] );

    if (! empty ( $matches [2] )) {
      $end = intval ( $matches [2] );
    }
  }
}

header ( 'HTTP/1.1 206 Partial Content' );

header ( "Content-Range: bytes $begin-$end/10000" );
foreach(range(0, 99) as $v){
  echo rand(1, 9);
}

请求之后,我们去看 Proxy 缓存目录,会发现生成了很多缓存。这就是因为我们每次都只是请求 100 字节范围内的数据,所以每次请求的响应就只有 100 字节,总共会响应 1000 个字节,大概有 10 次子请求。这里只有 8 个目录,但是还有二级目录,总共生成的缓存文件应该是 10 个。

[root@localhost article.http.d]# ll /usr/local/nginx/slicecache/
total 0
drwx------ 3 www www 16 Sep 20 09:58 0
drwx------ 3 www www 16 Sep 20 09:58 1
drwx------ 4 www www 26 Sep 20 09:58 3
drwx------ 3 www www 16 Sep 20 09:58 4
drwx------ 3 www www 16 Sep 20 09:58 5
drwx------ 3 www www 16 Sep 20 09:58 a
drwx------ 4 www www 26 Sep 20 09:58 c
drwx------ 3 www www 16 Sep 20 09:58 f

随便查看一个目录下面的缓存文件,内容就是 100 个字符。

[root@localhost article.http.d]# cat /usr/local/nginx/slicecache/3/25/2c87b23befe050b716282f3280b5c253
��)c��������-)c
  R
KEY: /slice/fastcgi1/slice/1.phpbytes=800-899
HTTP/1.1 206 Partial Content
Server: nginx/1.23.0
Date: Tue, 20 Sep 2022 01:58:05 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
X-Powered-By: PHP/7.2.24
Content-Range: bytes 800-899/1000

2687293144586783221846674348597775216172183988478888753581981981732616122451579567834463585161967919

这 100 个字符在最终整体返回的数据中肯定是存在的,是整体响应内容的连续一部分。

2a6fcf69926551f175422e1eed634c86.png

请求分流

最后我们再来看到的是请求分流的功能。它还是比较有意思的,能够根据一个变量内容,进行 Hash 分配到指定的内容,有点类似于之前学习过的 Redis 的分槽的效果。这个模块的全名是 ngx_http_split_clients_module 模块,用于创建适用于 A/B 测试的变量,也称为拆分测试。它直接包含在 Nginx 核心源码中,直接就可以使用,也只有一个配置指令。

split_clients

为 A/B 测试创建一个变量。

split_clients string $variable { ... }

只能在 http 模块下进行配置。使用 MurmurHash2 对原始字符串的值进行散列。和 Redis Cluster 中的 槽solt 类似,从 0 到 4294967295 的范围内,根据配置的结果,会让散列值落在一定的范围内。后面我们看例子再详细说明。

请求分流测试

上面的内容要是没看懂,我们就直接测试效果。

# http
split_clients "${arg_a}zyblog" $variant {
  50%               aaa.html;
  20%               a.txt;
  *                 index.html;
}

server {
  # ………………
  location /splitclient/ {
    alias html/;
    index $variant;
  }
}

在 split_clients 配置中,我们定义了 $arg_a 拼接 zyblog 字符串做为 Hash 值,也就说,根据我们传递过来的 GET 参数 a 的不同,就会有不同的哈希结果。上面配置的意思是,50% 代表散列结果为 0-2147483647 范围内的结果,就设置 $variant 为 aaa.html ;20% 代表散列值在 2147483648-3006477107 范围内的结果,$variant 为 a.txt ;剩下如果落在 3006477108 - 4294967295 范围内,则将变量的值设置为 index.html 。

这一块真的和 Redis Cluster 中相关的概念非常类似,如果不记得了,可以回到 Redis进阶:分布式部署RedisCluster(一) 这篇文章中,看一下 槽Slot 相关的说明。接下来就是测试了,不停地修改 a 参数的值就可以看到效果啦。

➜  ~ curl 'http://192.168.56.88:8034//splitclient/'
111222333444

<h1>aaa</h1>

➜  ~ curl 'http://192.168.56.88:8034//splitclient/?a=1'
this is a.txt. 111

➜  ~ curl 'http://192.168.56.88:8034//splitclient/?a=2'
111222333444

<h1>aaa</h1>

➜  ~ curl 'http://192.168.56.88:8034//splitclient/?a=3'
this is a.txt. 111

➜  ~ curl 'http://192.168.56.88:8034//splitclient/?a=4'
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!123123</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

总结

安全链接这个,是不是感觉有点意思啊,虽说大部分情况下我们会在动态语言中做接口签名,但静态资源有需要的时候完全也可以通过 Nginx 来实现嘛。这样不管动态还是静态资源,都是有请求限制的啦。

范围分片可能我们平常用得不多,大多数情况下可能是对一些下载文件做断点续传时会用到。

请求分流这个,其实可以实现更多的功能。因为我们可以设置变量,就可以将这个变量应用到 location、if、rewrite 等等各种配置中去,甚至分开记录日志都可以。非常强大,也非常灵活,期待各路高手大佬的开发咯,有好的案例也欢迎留言分享哦。

参考文档:

http://nginx.org/en/docs/http/ngx_http_secure_link_module.html

http://nginx.org/en/docs/http/ngx_http_slice_module.html

http://nginx.org/en/docs/http/ngx_http_split_clients_module.html

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

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

相关文章

python模块之feapder 爬虫框架

一、简介 官网&#xff1a;https://feapder.com/#/ feapder是一款上手简单&#xff0c;功能强大的Python爬虫框架&#xff0c;内置AirSpider、Spider、TaskSpider、BatchSpider四种爬虫解决不同场景的需求&#xff0c;但像任何工具一样&#xff0c;它也有其优点和缺点。以下是…

如何利用考培系统进行个性化学习和评估

考培系统作为一种现代化的学习和评估工具&#xff0c;可以为学生提供个性化的学习和评估服务。它利用先进的技术和算法&#xff0c;根据学生的学习情况和需求&#xff0c;为其量身定制学习计划&#xff0c;并提供相应的评估反馈。 1. 个性化学习 考培系统通过分析学生的学习情…

QML(25)——文本输入框组件的区别(TextField TextInput TextArea TextEdit)

目录 效果展示适用场景文本组件TextLabelText和Label的区别 单行文本输入框TextFieldTextInputTextField 和 TextInput的区别 多行文本输入框TextAreaTextArea 和 TextEdit 的区别 效果展示 适用场景 场景组件属性短文本Text长文本 末尾省略Textelide: Text.ElideRight文本设置…

通用FIFO设计深度8宽度64,verilog仿真,源码和视频

名称&#xff1a;通用FIFO设计深度8宽度64&#xff0c;verilog仿真 软件&#xff1a;Quartus 语言&#xff1a;verilog 本代码为FIFO通用代码&#xff0c;其他深度和位宽可简单修改以下参数得到 reg [63:0] ram [7:0];//RAM。深度8&#xff0c;宽度64 代码功能&#xff1a…

ArmSoM-RK3588编解码之mpp解码demo解析:mpi_dec_test

1. 简介 [RK3588从入门到精通] 专栏总目录 mpi_dec_test 是rockchip官方解码 demo 本篇文章进行mpi_dec_test 的代码解析&#xff0c;解码流程解析 2. 环境介绍 硬件环境&#xff1a; ArmSoM-W3 RK3588开发板 软件版本&#xff1a; OS&#xff1a;ArmSoM-W3 Debian11 3.…

低代码助力软件开发

低代码开发工具正在日益变得强大&#xff0c;它正不断弥合着前后端开发之间的差距。对于后端来说&#xff0c;基于低代码平台开发应用时&#xff0c;完全不用担心前端的打包、部署等问题&#xff0c;也不用学习各种框架&#xff08;Vue、React、Angular等等&#xff09;&#x…

GO 语言如何用好变长参数?

函数重载 对于函数重载相信编码过的 xdm 肯定不会陌生&#xff0c;函数重载就是在同一个作用域内定义多个具有相同名称但参数列表不同的函数 此处的参数列表不同&#xff0c;可以是参数的类型不同&#xff0c;参数的个数不同 那么我们一起分别来看看 C 语言&#xff0c;C 语…

物联网专业前景怎么样?

物联网专业前景怎么样&#xff1f; 物联网专业在当今技术发展迅速的背景下具有广阔的前景。以下是物联网专业的一些优势和就业前景&#xff1a; 1.市场需求大&#xff1a;物联网作为人工智能、云计算和大数据等技术的结合&#xff0c;已经成为许多行业的核心需求。各行各业都需…

【智能指针】

目录&#xff1a; 前言智能指针&#xff08;一&#xff09;智能指针初始了解内存泄漏1. 内存泄漏分类2. 如何检测内存泄漏3. 如何避免内存泄漏使用智能指针之前&#xff0c;异常安全的处理 &#xff08;二&#xff09;智能指针实现既原理智能指针RAII使用智能指针之后&#xff…

060:mapboxGL点击某处,通过flyTo,以动画的形式聚焦到此点

第060个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中点击某处,通过flyto,以动画的形式聚焦到此点。这里用到了flyTo的方法,里面可以设置bearing,zoom,pitch等众多的属性内容。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实现效果 文章目录 示…

数据结构与算法-(10)---列表(List)

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

Linux 最大可以打开多少文件描述符?

Linux 最大可以打开多少文件描述符&#xff1f; 在日常开发中&#xff0c;对文件的操作可谓是再寻常不过的意见事情。那么你是否有这样一个疑问&#xff0c; 我最多可以打开多少个文件呢&#xff1f; 在Linux系统中&#xff0c;当某个程序打开文件时&#xff0c;内核返回相应…

SQL查询命令互转vba格式

最近搞个Excel的vba查询数据库&#xff0c;发现vba有代码行长度限制需要转换下就弄了这个&#xff0c;布局和功能暂且这样了&#xff0c;哪位大佬如果有兴趣的可以再美化下&#xff01; 这次更新了SQL命令互转VBA格式&#xff0c; SQL原始格式要分行的不能一坨贴进去&#xff0…

Java日志系统之JUL

目录 JUL介绍 JUL的使用 日志级别 指定日志输出地址 Logger对象的父子关系 Logger读取配置文件 JUL介绍 Java自带的框架&#xff0c;使用简单&#xff0c;无需引入依赖 JUL的使用 public class JULTest {Testpublic void testLogger() throws Exception{//获取日志记录…

2 用TensorFlow构建一个简单的神经网络

上一篇&#xff1a;1 如何入门TensorFlow-CSDN博客 环境搭建 后续介绍的相关代码都是在pycharm运行&#xff0c;pycharm安装略。 打开pycharm&#xff0c;创建一个新的项目用于tensorflow编码练习&#xff0c;在Terminal输入命令&#xff1a; # 依赖最新版本的pip pip inst…

[AutoSAR系列] 1.2 AutoSar 综述

AutoSAR是一种汽车工业领域的标准化软件架构,旨在简化不同汽车制造商之间的软件开发和交互。该标准于2003年由一系列欧洲汽车制造商成立的AutoSAR联盟制定并发布,目前已经成为全球范围内的标准。下面将对AutoSAR的概念、架构和实现进行综述。 1. 概述 AutoSAR是汽车电子控制…

Qt 读写文件(QFileQTextStreamQDataStream) 详解

一、读写文本文件 (QFile 类) Qt QFile类是一个用于读取和写入文件的类&#xff0c;它提供了对文件的访问、读取和写入等操作。它既可以操作文本文件&#xff0c;也可以操作二进制文件。 QFile类的功能包括&#xff1a; 打开、关闭文件读取文件内容写入文件内容支持文本模式…

如何让ChatGPT生成图片?

目录 一、那么如何解决让ChatGPT具有画图能力的问题呢&#xff1f; 二、那ChatGPT为什么能生成图片呢&#xff1f; 我们都知道ChatGPT只是个纯文本的AI模型&#xff0c;不具备画图能力。它可以生成文本&#xff0c;但如果让他生成图片就会显示如下的声明&#xff1a; 但通过本…

前端多媒体处理工具——ffmpeg的使用

写在前面 在前端领域&#xff0c;FFmpeg 是一个非常有用的工具&#xff0c;它提供了多种媒体格式的封装和解封装&#xff0c;包括多种音视频编码、多种协议的流媒体、多种色彩格式转换、多种采样率转换、多种码率切换等。可以在多种操作系统安装使用。 安装 下载FFmpeg 在网…

服务器数据恢复-某银行服务器硬盘数据恢复案例

服务器故障&分析&#xff1a; 某银行的某一业务模块崩溃&#xff0c;无法正常使用。排查服务器故障&#xff0c;发现运行该业务模块的服务器中多块硬盘离线&#xff0c;导致上层应用崩溃。 故障服务器内多块硬盘掉线&#xff0c;硬盘掉线数量超过服务器raid阵列冗余级别所允…