Grpc+HTTP/2
在上文我们通过Java来实现了Grpc的使用,但是有一点我们注意到,虽然使用的是HTTP/2协议进行通信的,但是为什么我们使用的是PLAINTEXT,HTTP/2的实现中间不是有一层TLS/1.2+吗,没证书还能给我整上加密了???
其实在HTTP/2的实现当中有一种h2c的协议升级方式,这种方式就是不带有加密TLS的协议。
H2C明文HTTP/2
普通浏览器实现HTTP/2需要先使用HTTP/1.x来请求服务器,在获取到服务器Upgrade:h2c(明文)返回后来转换协议
| 客户端 服务端 | 
客户端的前言内容包含一个内容为 PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n 的序列加上一个可以为空的 SETTINGS 帧,在收到 101(Switching Protocols) 响应 (代表 upgrade 成功) 后发送,或者作为 TLS 连接的第一个传输的应用数据。
如果在预先知道服务端支持 HTTP/2 的情况下启用 HTTP/2 连接,客户端连接前言在连接建立时发送。
我们的GRPC就是已知直接使用HTTP/2的情形,所以在建立连接的时候不需要HTTP/1.X来升级协议,在TCP握手之后直接使用Magic帧来确定协议
H2 TLS加密的HTTP/2
当然对于带有TLS的HTTP/2就不会通过HTTP/1.X来升级协议,他们会直接使用HTTPS来协商
HTTPS需要经过一个协议协商阶段来建立连接,在建立连接并交换HTTP消息之前,它们需要协商 SSL/TLS协议、加密的密码,以及其他的设置。这个过程比较灵活,可以引入新的HTTPS协议和密码,只要客户端和服务端都支持就行。在HTTPS握手的过程中,可以同时完成HTTP/2协商,这就不需要在建立连接时增加一次跳转。
上面提到的协商协议阶段就是使用ALPN来进行协商使用的协议
- 
客户端发起 TLS 握手: 客户端在发起 TLS 握手请求时,会在 “ClientHello” 消息中包含一个 ALPN 扩展字段,列出它支持的协议列表,例如 http/1.1 和 h2(HTTP/2 的标识符)。 
- 
服务器响应: 服务器收到 “ClientHello” 消息后,在 “ServerHello” 消息中包含一个 ALPN 扩展字段,选择并响应一个客户端支持的协议,例如 h2,如果服务器支持 HTTP/2 并且客户端也支持。 
- 
建立 TLS 连接: 协商完成后,客户端和服务器按照协商的协议版本进行通信,并完成 TLS 握手过程。 
这是正常HTTP/2的协议流程
使用TLS加密的Grpc
那我们该如何才能让我们的grpc使用TLS加密呢
前期准备
将配置的grpc.client.feignName.negotiationType=PLAINTEXT删掉,配置这种情况表示走明文
需要让我们的服务支持HTTPS
我这边使用的是通义零码直接帮我做的
- 首先创建一个生成证书的配置,csm-csm是你服务在注册中心的名字,当然还有dns2,直接指向注册中心后面的域名也可以[req] 
 default_bits = 2048
 prompt = no
 default_md = sha256
 distinguished_name = dn
 req_extensions = v3_req
 [dn]
 C = CN
 ST = Beijing
 L = Beijing
 O = Baiwang
 OU = IT
 CN = csm-csm
 [v3_req]
 basicConstraints = CA:FALSE
 keyUsage = nonRepudiation, digitalSignature, keyEncipherment
 subjectAltName = @alt_names
 [alt_names]
 DNS.1 = csm-csm
 DNS.2 = localhost
 DNS.3 = 127.0.0.1
- 通过配置文件生成证书openssl req -new -x509 -newkey rsa:2048 -sha256 -keyout server.key -out server.crt -days 365 -nodes -config openssl.cnf -extensions v3_req 
- 查看证书创建是否准确验证生成的证书是否包含正确的SAN 
 openssl x509 -in server.crt -text -noout | grep -A5 "Subject Alternative Name"
 返回内容
 X509v3 Subject Alternative Name:
 DNS:csm-csm, DNS:localhost, DNS:127.0.0.1
 X509v3 Subject Key Identifier:
 CB:6D:C5:23:E1:99:CC:B3:74:DC:B3:8F:5C:1D:0A:05:2A:EE:18:CB
 Signature Algorithm: sha256WithRSAEncryption
 Signature Value:
 检查证书的完整信息
- 配置服务端的Grpcgrpc: 
 server:
 port: 9099
 security:
 enabled: true
 certificate-chain: classpath:certificates/server.crt
 private-key: classpath:certificates/server.key
配置客户端的Grpc
| grpc: | 
这样我们在使用grpc调用的时候就是带证书的访问了
未使用TLS
使用TLS
这两张图片完整的表示了HTTP/2的ALPN
因为被证书加密了,我们也无法看到传输的具体内容,甚至请求URL也看不到了(HTTPS的是可以看到的,我并不确定这两者的区别)

