NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

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:164205

评论

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

Java 在Word文档中添加艺术字

在下毛毛雨

Java word 添加艺术字

【DBA100人】胡中豪:国产分布式数据库DBA炼成记

OceanBase 数据库

对话杨传辉:国产数据库新战绩背后,OceanBase坚持自研的初心与决心

OceanBase 数据库

高端扫地机销量占比全球第一 石头科技创新驱动增长

科技热闻

jdbcs之连接池和框架

楠羽

JDBC 笔记 9月月更

24小时的客户服务如何实现?来建立产品知识库吧!

Baklib

产品 知识库 客户服务

C++ STL【常用算法】详解

Fire_Shield

算法 stl 9月月更

XDR的技术栈参考

极盾科技

网络安全 数据安全 xdr

如何理解「数字化转型的本质是人的转型」?

BizFree

数字化转型 工业4.0 智能制造 机器换人 数字化工具

数据库系统助力企业降本增效的技术要点|Meetup 回顾与预告

OceanBase 数据库

高效工作,文档协作必不可少

Baklib

高效工作 文档协作

Sovit3D数字孪生智慧港口三维可视化解决方案

数据可视化平台

物联网 智慧港口 5G智慧港口 港口三维可视化 智慧港口解决方案

开发者必读:2022年移动应用技术趋势白皮书

HMS Core

CLIP-as-service 升级啦!

Jina AI

开源 算法 神经搜索

ShareSDK Android端分享与授权示例代码

MobTech袤博科技

android sdk

如何理解「数字化是 IT 公司在给传统企业贩卖焦虑」?

BizFree

数字化转型 企业 焦虑 智能制造

2个原则,8个小撇步,带你探究 Dockerfile 在工程实践中的实战技巧!

Jina AI

Dockfile

中小企业如何有效应对计算资源的弹性变化需求?

阿里巴巴中间件

阿里云 Serverless 云原生 中小企业

得物云原生全链路追踪Trace2.0架构实践

得物技术

云原生 监控 链路追踪 OpenTelemetry 企业号九月金秋榜

ShareSDK Android端微信回调冲突解决方案

MobTech袤博科技

android sdk

云对象 - 重新定义前后端交互

崔红保

uni-app Serverless unicloud

OpenSSF发布npm 最佳实践指南,应对开源依赖风险

SEAL安全

npm DevSecOps 开源安全 软件供应链安全 开源安全与治理

5年专业研究,这份云原生安全指南请查收!

博文视点Broadview

我们的月饼不一样!来线上 DIY 微软限定款

Azure云科技

技术 活动报名

不清楚产品帮助中心怎么设置?从这几点出发!

Baklib

产品 帮助中心

库调多了,都忘了最基础的概念-《线程池篇》

知识浅谈

线程池 9月月更

力扣20 - 有效的括号【暴力、分支判断、哈希表】

Fire_Shield

算法 哈希表 9月月更

FlyFish开发者说|开源低代码平台的体验与思考

云智慧AIOps社区

前端 低代码 开源项目 数据可视化 可视化大屏

一文详解东数西算下绿色数据中心节能减排十大技术、智算中心八大趋势

蓝海大脑GPU

SpringBoot源码 | printBanner方法解析

六月的雨在InfoQ

源码 springboot 9月月更 springboot源码

数字藏品电商平台开发:如何开发数字藏品?

开源直播系统源码

区块链 NFT 数字藏品 数字藏品系统 数字藏品软件

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