写点什么

HTTP/2 探索第二篇——工具及应用

  • 2019-08-22
  • 本文字数:8569 字

    阅读完需:约 28 分钟

HTTP/2探索第二篇——工具及应用

目录结构:

HTTP/2 环境搭建 Step by step

wireshark 使用

fiddler 使用(会持续更新)

nginx 的简单配置

h2o 服务器及其 Server Push 策略思想简介 —— h2o 实现的可感知缓存的 Server Push,我们借用终端的力量应该能实现的更好

curl —— 涉及到 HTTP2 的调试

nghttp —— 一个 HTTP2 客户端请求工具,可以显示出请求的 Frame

nghttpd —— 一个 HTTP2 服务器搭建工具,可以搭建可 Server Push 的服务器

软件安装

一、证书 —— 自签发证书和 Lets Encrypt 证书申请

二、基本工具

三、服务器准备

四、开发准备

SSL/TLS 部分小贴士

活用证书提高性能

HSTS 和 CSP 提高安全

系列文章

Reference

HTTP/2 环境搭建 Step by step

本文需要安装的软件为(Mac 用户请使用 homebrew 来安装,括号里都是 Mac 的安装方式)


curl (brew install nghttp2 —with-nghttp2)


wget https: //curl .haxx.se/download/curl-7.48.0.tar.gz


tar xvf curl-7.48.0.tar.gz && cd curl-7.48.0


然后输入以下命令,exit 一次再进入然后版本是 7.48 就成功鸟:


  $ ./configure --with-nghttp2=/usr/local --with-ssl  $ make  $ sudo make install  $ ldconfig  $ usr/local/bin/curl -V
复制代码


Linux 安装


nghttp2 (brew install nghttp2)


安装网址


sudo apt-get install g++ make binutils autoconf automake autotools-dev libtool pkg-config \zlib1g-dev libcunit1-dev libssl-dev libxml2-dev libev-dev libevent-dev libjansson-dev \libjemalloc-dev cython python3-dev python-setuptools
复制代码


上面是安装依赖,之后就可以编译了:


$ autoreconf -i$ automake$ autoconf$ ./configure$ make$ sudo make installnginx (brew install nginx —devel)
复制代码


增加以下两行,其中 $codename 自行去该网站查询,比如 Ubuntu 14.04 是 trusty;


  deb http://nginx.org/packages/mainline/ubuntu/ $codename nginx  deb-src http://nginx.org/packages/mainline/ubuntu/ $codename nginx
复制代码


Linux 安装


vim 到/etc/apt/sources.list


然后 sudo apt-get update && sudo apt-get install nginx 就可以装最新支持 HTTP2 的 nginx 啦;


apache (brew install httpd24 —with-http2)[本文重点讲解 nginx]


Linux 安装

一、证书

自签发


打开提供的 Demo 文件,terminal 打开/keys 路径,输入./ca.sh http2test .com,也可以生成其他域名或泛域名(*.xx.com)。注意:也可以不用生成证书,直接使用 keys 文件下提供的 http2test.com 证书;

Let’s Encrypt

打开 Let’s Encrypt 的官网,这里讲解如果已经启动 nginx 的情况下,如何签发证书。


步骤:


首先需要把代码克隆下来:git clone https: //github. com/letsencrypt/letsencrypt && cd letsencrypt


然后./letsencrypt-auto --help 会执行一些初始化工作,并且显示支持的命令;


比如我的 web 目录在~/www 下,此步骤需要已搭建好服务器,并且可以通过 example.com 访问~/www 里的内容,如果是动态网站,需要在 nginx 层设置一个映射,将/.well-known/acme-challenge 映射到刚设置好的目录,也就是~/www。


  location /.well-known/acme-challenge {      root /home/$username/www;  }
复制代码


(需要 nginx 已经装好,没装好的完成下面的 nginx 部分后再回来设置)那么./letsencrypt-auto certonly --webroot -w ~/www -d example. com,example.com 是你希望申请证书的域名,然后证书下发成功。


然后在 nginx 中设置证书信息


  ssl_certificate /etc/letsencrypt/live/$example.com/fullchain.pem;  ssl_certificate_key /etc/letsencrypt/live/$example.com/privkey.pem;
复制代码


然后 sudo nginx -t && sudo nginx -s reload 就可以看到啦

二、基本工具

curl

curl 的基本用法是:


curl -v -o /dev/null --http2 http://nghttp2.org
复制代码


这里输入的是 HTTP 而不是 HTTPS 是因为,这里会采用 HTTP2 的 ClearText 模式,使用 101 改变协议协商升级为 HTTP2 协议。


Connected to nghttp2.org (106.186.112.116) port 80 (#0)> GET / HTTP/1.1> Host: nghttp2.org> User-Agent: curl/7.48.0> Accept: */*> Connection: Upgrade, HTTP2-Settings> Upgrade: h2c> HTTP2-Settings: AAMAAABkAAQAAP__>< HTTP/1.1 101 Switching Protocols< Connection: Upgrade< Upgrade: h2c* Received 101* Using HTTP2, server supports multi-use* Connection state changed (HTTP/2 confirmed)* TCP_NODELAY set* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=21* Connection state changed (MAX_CONCURRENT_STREAMS updated)!< HTTP/2.0 200< date:Sun, 10 Apr 2016 16:52:43 GMT< content-type:text/html< content-length:6646< last-modified:Sun, 03 Apr 2016 06:53:14 GMT< etag:"5700bdda-19f6"< link:</stylesheets/screen.css>; rel=preload; as=stylesheet< accept-ranges:bytes< x-backend-header-rtt:0.000625< server:nghttpx nghttp2/1.10.0-DEV< via:2 nghttpx< x-frame-options:SAMEORIGIN< x-xss-protection:1; mode=block< x-content-type-options:nosniff<
复制代码


现在的大多数网站,都是通过 302 跳转到 HTTPS 网站来协商升级的,例如我厂的 QQ 邮箱;


Connected to mail.qq.com (183.60.15.162) port 80 (#0)> GET / HTTP/1.1> Host: mail.qq.com> User-Agent: curl/7.48.0> Accept: */*> Connection: Upgrade, HTTP2-Settings> Upgrade: h2c> HTTP2-Settings: AAMAAABkAAQAAP__>< HTTP/1.1 302 Found< Server: TWS< Connection: close< Date: Sun, 10 Apr 2016 16:58:48 GMT< Content-Type: text/html; charset=GB18030< Location: https://mail.qq.com/cgi-bin/loginpage< Content-Length: 0<
复制代码

nghttp

官方文档,安装 nghttp2 后有配套的 nghttp 客户端、nghttpd 服务器、nghttpx 反向代理、h2load 负载测试等工具。


输入命令 nghttp -nv https: //nghttp2. org (n 代表不输出,v 代表详细信息):


结果列出了连接过程中的 HTTP2 各个 Stream 信息,例如 SETTINGS Frame,HEADER Frame 等,也可以带上参数:


[  0.170] ConnectedThe negotiated protocol: h2[  0.732] recv SETTINGS frame <length=12, flags=0x00, stream_id=0>          (niv=2)          [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]          [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535][  0.732] send SETTINGS frame <length=12, flags=0x00, stream_id=0>          (niv=2)          [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]          [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535][  0.732] send SETTINGS frame <length=0, flags=0x01, stream_id=0>          ; ACK          (niv=0)[  0.732] send PRIORITY frame <length=5, flags=0x00, stream_id=3>          (dep_stream_id=0, weight=201, exclusive=0)[  0.732] send PRIORITY frame <length=5, flags=0x00, stream_id=5>          (dep_stream_id=0, weight=101, exclusive=0)[  0.732] send PRIORITY frame <length=5, flags=0x00, stream_id=7>          (dep_stream_id=0, weight=1, exclusive=0)[  0.732] send PRIORITY frame <length=5, flags=0x00, stream_id=9>          (dep_stream_id=7, weight=1, exclusive=0)[  0.732] send PRIORITY frame <length=5, flags=0x00, stream_id=11>          (dep_stream_id=3, weight=1, exclusive=0)[  0.732] send HEADERS frame <length=36, flags=0x25, stream_id=13>          ; END_STREAM | END_HEADERS | PRIORITY          (padlen=0, dep_stream_id=11, weight=16, exclusive=0)          ; Open new stream          :method: GET          :path: /          :scheme: https          :authority: nghttp2.org          accept: */*          accept-encoding: gzip, deflate          user-agent: nghttp2/1.9.1[  0.891] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>          ; ACK          (niv=0)[  0.891] recv (stream_id=13) :method: GET[  0.891] recv (stream_id=13) :scheme: https[  0.892] recv (stream_id=13) :path: /stylesheets/screen.css[  0.892] recv (stream_id=13) :authority: nghttp2.org[  0.892] recv (stream_id=13) accept-encoding: gzip, deflate[  0.892] recv (stream_id=13) user-agent: nghttp2/1.9.1[  0.892] recv PUSH_PROMISE frame <length=47, flags=0x04, stream_id=13>          ; END_HEADERS          (padlen=0, promised_stream_id=2)[  0.892] recv (stream_id=13) :status: 200[  0.892] recv (stream_id=13) date: Sun, 10 Apr 2016 17:00:25 GMT[  0.892] recv (stream_id=13) content-type: text/html[  0.892] recv (stream_id=13) content-length: 6646[  0.892] recv (stream_id=13) last-modified: Sun, 03 Apr 2016 06:53:14 GMT[  0.892] recv (stream_id=13) etag: "5700bdda-19f6"[  0.892] recv (stream_id=13) link: </stylesheets/screen.css>; rel=preload; as=stylesheet[  0.892] recv (stream_id=13) accept-ranges: bytes[  0.892] recv (stream_id=13) x-backend-header-rtt: 0.000663[  0.892] recv (stream_id=13) strict-transport-security: max-age=31536000[  0.892] recv (stream_id=13) server: nghttpx nghttp2/1.10.0-DEV[  0.892] recv (stream_id=13) via: 2 nghttpx[  0.892] recv (stream_id=13) x-frame-options: SAMEORIGIN[  0.892] recv (stream_id=13) x-xss-protection: 1; mode=block[  0.892] recv (stream_id=13) x-content-type-options: nosniff[  0.892] recv HEADERS frame <length=266, flags=0x04, stream_id=13>          ; END_HEADERS          (padlen=0)          ; First response header[  0.893] recv DATA frame <length=6646, flags=0x01, stream_id=13>          ; END_STREAM[  0.893] recv (stream_id=2) :status: 200[  0.893] recv (stream_id=2) date: Sun, 10 Apr 2016 17:00:25 GMT[  0.893] recv (stream_id=2) content-type: text/css[  0.893] recv (stream_id=2) content-length: 39082[  0.893] recv (stream_id=2) last-modified: Sun, 03 Apr 2016 06:53:14 GMT[  0.893] recv (stream_id=2) etag: "5700bdda-98aa"[  0.893] recv (stream_id=2) accept-ranges: bytes[  0.893] recv (stream_id=2) x-backend-header-rtt: 0.000427[  0.893] recv (stream_id=2) strict-transport-security: max-age=31536000[  0.893] recv (stream_id=2) server: nghttpx nghttp2/1.10.0-DEV[  0.893] recv (stream_id=2) via: 2 nghttpx[  0.893] recv (stream_id=2) x-frame-options: SAMEORIGIN[  0.893] recv (stream_id=2) x-xss-protection: 1; mode=block[  0.893] recv (stream_id=2) x-content-type-options: nosniff[  0.893] recv (stream_id=2) x-http2-push: 1[  0.893] recv HEADERS frame <length=62, flags=0x04, stream_id=2>          ; END_HEADERS          (padlen=0)          ; First push response header[  1.407] recv DATA frame <length=16384, flags=0x00, stream_id=2>[  1.563] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>          (window_size_increment=33412)[  1.740] recv DATA frame <length=16384, flags=0x00, stream_id=2>[  1.741] recv DATA frame <length=6314, flags=0x01, stream_id=2>          ; END_STREAM[  1.741] send GOAWAY frame <length=8, flags=0x00, stream_id=0>          (last_stream_id=2, error_code=NO_ERROR(0x00), opaque_data(0)=[])
复制代码


还有这些参数:


-v : 显示详细信息-n : 不输出请求返回数据内容-t : 请求超时设置-w : 设置初始窗口大小-a : 解析页面获取页面上的资源-H : 给请求增加特定头部信息,例如 -H':method:PUT'-p : 设置请求权重--no-dep : 不发送依赖信息
复制代码

nghttpd

官方文档,使用 nghttpd,可以架设一个简易的支持 HTTP2 的服务器。打开附件中的示例文件,在路径 demos/nghttp/里有一个 run.sh(需要以管理员权限执行)


$ cd demos/nghttp$ sudo ./run.sh [server-push]
复制代码


就可以执行提供的 shell 脚本,第三个参数 server-push 是可选的,如果不需要 server-push 功能,直接 sudo ./run.sh 就可以了,在本地设置好 host 127.0.0.1 http2test.com 后,就可以在本地浏览器中访问了,路径是https://http2test.com/examples/dashboard/。由于自签的证书不被信任,需要安装公钥 keys/*.crt 文件并信任(Mac 中需要打开 keychain 这个软件,然后找到刚安装的证书,改为总是信任),安装信任后,打开 Chrome 就不会提示警告了;


如果需要开启 server-push 功能,输入指令 sudo ./run.sh server-push,shell 脚本里设置了-p/examples/dashboard/=/examples/dashboard/d3.js,当请求路径/examples/dashboard/时,就推送/examples/dashboard/d3.js 文件。

三、服务器准备

nginx

nginx 的 conf 文件里的设置,设置完后需要 sudo nginx -s reload,由于 nginx 的 ngx_http_v2_module 模块是替代以前的 ngx_http_spdy_module,故开启 HTTP2 支持后,就无法同时开启 SPDY 支持:


    server {        listen       443 ssl http2;        server_name  http2test.com;        ssl_certificate      $证书地址;        ssl_certificate_key  $证书私钥地址;        ssl_session_cache    shared:SSL:1m;        ssl_session_timeout  5m;        ssl_ciphers  HIGH:!aNULL:!MD5;        ssl_prefer_server_ciphers  on;        location / {            root   $静态文件地址;            index  index.html index.htm;        }    }
复制代码

h2o

这里引入下 Server Push 的概念,在上一篇概念篇有介绍道,Server Push 就是,当请求时,服务器同时将其它文件也推送过来,HTTP2 的说明中,并没有规定 Server Push 具体的实现策略,这个可由服务器和客户端自主决定:


Jetty:jetty 通过 referrer 建立了一个依赖模型,该模型可以应用在 CDN 里,方便配置;

h2o:通过 Cookie 实现了 cache aware server push——可感知缓存的服务器推送。第一次推送时,服务器端 set-cookie,将要推送的路径+etag 存入一个集合,通过算法生产指纹编码为 base64 存入 cookie,之后通过 cookie 来判断是否需要推送该文件;


这里着重介绍 h2o,为什么 h2o 要这么做呢?因为流量就是钱啊。。。客户端接收到服务器端发送的 PUSHPROMISE Frame 后,可以通过是否发送 RST Frame 来拒绝掉服务器推送的文件,但是在这个过程中,服务器推送的文件可能已经发送一部分过来了,如果客户端决定不接收服务器推送的文件,那么之前发送的部分就是浪费掉的流量,h2o 就是为了解决这个问题;在设置好 h2o 后,我们来看看第一次访问的结果:



让我们来看看第二次访问的结果:



可以看到,第二次访问时,并没有 PUSHPROMISE Frame 了,也就是说,服务器不再推送文件了。

四、开发准备

wireshark

这里讲解基本的 wireshark 使用,由于大多数的 HTTP2 都是基于 Over TLS 版,也就是需要解密才能看到正确的 HTTP2 包内容;wireshark 提供了两个方式:


使用 SSLKEYLOGFILE,使得 wireshark 可以使用 Firefox/Chrome 的解密信息


首先在 wireshark 的 Preferences -> Protocol -> SSL 配置一个可读的文件地址,然后在环境变量,例如 Mac 是~/.bashprofile:



export SSLKEYLOGFILE=$刚配置的地址


source ~/.bashprofile


通过 Terminal 打开 Firefox 或 Chrome,这样才能使用环境变量 SSLKEYLOGFILE:


open -a Google\ Chrome


该方法的局限是,只能在电脑上抓包使用,并且只能使用 Chrome 和 Firefox;


还有一个方法是配置 RSA 私钥,不过这种办法的局限是多种加密方式不支持,并且该方法必须纪录完整的 TLS 握手过程,所以建议打开浏览器访问前就已经开始监听;


配置好解密方式后,使用浏览器打开刚跑起来的 HTTP2 Demo,https: //http2test. com/examples/dashboard/,然后再筛选出输入 http2 并回车,就可以看到筛选的 HTTP2 包。


fiddler

fiddler 解密 HTTPS 采用的是中间人攻击的方法,客户端访问到 fiddler 代理服务器,然后 fiddler 代理服务器再模拟客户端访问到网站。那么,需要安装 Fiddler 的根认证证书,同时启用 HTTPS 解密功能。



对于 Fiddler 来说,对于每个机器其实下发的其实是不同的根证书,所以,一定要通过 Fiddler 的配置网页来安装证书(配置代理后,打开网站 http://ipv4.fiddler:8888,然后点击图中的 FiddlerRoot Certificate 来下载安装)



针对 iOS 及部分高版本的 Android,证书中的部分信息是必要的,有两个办法。1) 采用如图所示的设置(iOS 9 亲测可用),2) 安装使用 Fiddler CertMaker 插件



然后需要介绍的一个点是 FiddlerScript,这是一个很强大的功能。如果需要将以前调试 HTTP 的方法在 HTTPS 同样适用,需要有这些设置。部分设置可以参考 Qzone https+SPDY 实施 扩展篇:debug with https,然后之后我也会继续更新 Fiddler 调试部分的内容,请收藏哦。在 Willow 的 rule 里设置 HTTPS -> HTTP; HTTPS -> File; 都是可以生效的。


如果需要 HTTPS -> HTTPS 或者 HTTPS -> HTTP,可以采用上面链接的方法,也可以设置 oSession[“x-replywithtunnel”] = “FakeTunnel”。


if (oSession.HostnameIs("app.yourdomain.com")){    // Handle CONNECT Tunnels    if (oSession.HTTPMethodIs("CONNECT"))    {        oSession["x-replywithtunnel"] = "FakeTunnel";        return;    }
oSession.fullUrl = "http://somedomain:someport" + oSession.PathAndQuery;}
复制代码

SSL/TLS 部分小贴士

一、活用证书,提高性能

首先来看本地搭建的 HTTPS 服务:


第一个情况是,同一个 IP,但是域名不同,同时,使用的证书也不同:第一张图显示的域名是 http2test. com,第二张图显示的域名是 http2 .icese7en. com,他们使用的证书也是不同的,可以看到 TCP Stream 这一列,具有不同的序号(相同序号表明他们使用的是同一个 TCP 连接)




第二个情况是,同一个 IP,域名不同,但是使用的证书是相同的:第一张图的域名是 cdn1. http2test. com,第二张图的域名是 cdn2. http2test. com,他们使用的证书(第三张图)是泛域名*.http2test. com,他们的 TCP Stream 序号都是 30,复用同一条 TCP 连接




那么,如果域名不同,甚至都不是子域名的方式,也可以通过这一个点去优化吗?是可以的,通过证书里的 subjectAltName,我们可以在证书里管理多个不同域名,例如 google 的证书:



不过这样证书很贵就是了 - -

二、SSL/TLS 提高安全

HSTS——HTTP 严格传输协议

HSTS 主要是为了改善以下几个问题:


没办法知道一个网站是否支持 TLS:例如第一次连接时,如果没有指定协议名,会优先采用 http 协议,有安全隐患。而开启 HSTS 后,第一次(之前访问过该域名)之后的访问浏览器会自动强制使用 HTTPS 访问;


对证书问题的宽容:未开启 HSTS 时,如果证书有问题,客户端只会提示警告,而不是禁止访问,开启 HSTS 后,会被禁止访问;


mixed-content 问题:开启 HSTS 后,一个 HTTPS 页面上的同域名下的非 HTTPS 资源会自动升级为 HTTPS 访问;


要开启 HSTS,只需要服务器端在返回头中返回(不支持 IP)


Strict-Transport-Security: max-age=31536000 [; includeSubDomains] [; preload]# includeSubDomains 可以开启子域名的HSTS功能# 不过需要评估这么做的是否会有负面影响
复制代码


在 max-age 指定的时间内,浏览器都自动以 HTTPS 访问。如果需要关闭 HSTS,返回 max-age=0 就可以了。


注意


HSTS 的第一次访问仍然具有被挟持的危险,可通过 HSTS preload 来减轻影响(需要申请加入各浏览器的 preload-list);


HSTS 时间是基于本地时间计算的,如果客户端时间被篡改,可能会造成 HSTS 策略被失效绕过。


引用自关于启用 HTTPS 的一些经验分享(一)


只要你不能确保永远提供 HTTPS 服务,就不要启用。因为一旦 HSTS 生效,你再想把网站重定向为 HTTP,之前的老用户会被无限重定向,唯一的办法是换新域名

CSP——内容安全政策

CSP 是一个声明式的安全机制,原本的目的是防止 XSS 跨站脚本攻击。例如,CSP 可以完全禁止内联的 Javascript 代码的执行,控制哪些外联的 Javascript 文件可以被执行。


Content-Security-Policy: default-src 'self'; img-src *; script-src scripts.example.com
复制代码


上面的 CSP 策略是,默认允许本源的资源的访问,允许所有 URL 的图片显示,外链脚本只允许来自于 scripts.example.com 的文件执行;


Content-Security-Policy: default-src https: 'unsafe-inline' 'unsafe-eval'; connect-src https:
复制代码


上面的 CSP 策略是,默认允许来自于任何 URL 的资源,只要它是安全的 HTTPS,同时开启了内联 JS 和 eval 的执行(默认是被 CSP 禁止的),connect-src 设定了 Ajax 请求只能请求 HTTPS;(部分开启内联 JS 的执行可参考 Content Security Policy Level 2 介绍)

CSP 上报

使用 report-uri 指令,违反 CSP 策略的行为都会被上报到该 CGI


本文转载自公众号小时光茶舍(ID:gh_7322a0f167b5)。


原文链接:


https://mp.weixin.qq.com/s/Y1x0GUkfRbWEz6YsJrMTAQ


2019-08-22 20:164197

评论

发布
暂无评论
发现更多内容

信息系统的建设周期

奔向架构师

信息系统 5月月更

Mysql的事务操作问题

恒山其若陋兮

MySQL 5月月更

nginx配置系列(十)代理服务(proxy_pass)

乌龟哥哥

5月月更

用阅读和写作应对未来风险

石云升

写作 阅读 5月日更

【Python】题集 of ①

謓泽

5月月更

虎符交易所Hoo研究院|币海寻珠 2022年4月下半月区块链投融事件TOP20

区块链前沿News

虎符研究院

linux时间格式化命令

入门小站

Linux

网站开发进阶(三十九)重磅推出:优良的编码风格!

No Silver Bullet

5月月更 编码风格

网站开发进阶(四十四)input type=“submit“ 和“button“的区别

No Silver Bullet

5月月更 button submit

Intellij官方中文语言包,它来了

FunTester

正向代理与反向代理

HoneyMoose

遇到bug怎么分析,这篇文章值得一看

伤心的辣条

Python 程序人生 软件测试 自动化测试 测试开发

【PIMF】OpenHarmony啃论文俱乐部——拼音输入法原理_从触摸事件到汉字

离北况归

OpenHarmony Openharmony啃论文俱乐部 OpenHarmony应用开发 PIMF团队

上海疫情封控期间,模拟芯片巨头变相裁员后续:补偿是不可能补偿的!

IC男奋斗史

职业规划 裁员 芯片

【刷题第2天】买卖股票的最佳时机

白日梦

5月月更

从手工测试到自动化测试进阶,需要学什么?结合自身分享我10+年的测试经验!

伤心的辣条

Python 程序人生 软件测试 自动化测试 接口测试

【愚公系列】2022年05月 二十三种设计模式(七)-桥接模式(Bridge Pattern)

愚公搬代码

5月月更

Python 实现设计模式之工厂模式

宇宙之一粟

Python 设计模式 工厂模式 5月月更

Docker下的Spring Cloud三部曲之三:在线横向扩容

程序员欣宸

Spring Cloud java 5月月更

飞桨云上沙龙——智能制造专场

百度大脑

Flutter 组件渲染模式详解

岛上码农

flutter ios 安卓开发 跨平台应用 5月月更

在线TSV转Excel(xls/xlsx)

入门小站

工具

第八周作业

Asha

Nginx 和 Apache 配置 SSL 文件签名的不同

HoneyMoose

TypeScript 里的 Reference Type 和 Triple-Slash Directives

Jerry Wang

typescript 编程语言 angular 5月月更 directive

渗透测试工具一一Nmap(从初级到高级)

网络安全学海

网络安全 渗透测试 WEB安全 漏洞挖掘 nmap

LabVIEW仪器控制:智能示波器(普源DS1000E)

不脱发的程序猿

LabVIEW 串口通信 VISA LabVIEW示波器软件

模块一

Geek_28cf33

观测云产品更新|优化观测云商业版升级流程;新增进程、日志、链路详情页关联网络;场景模块优化等

观测云

运维 可观测性 可观测

在线URL解码还原工具

入门小站

工具

k8s client-go源码分析 informer源码分析(2)-初始化与启动分析

良凯尔

容器 云原生 #Kubernetes# Client-go

HTTP/2探索第二篇——工具及应用_语言 & 开发_张浩然_InfoQ精选文章