http
如何实现 http
http 1.1 vs http2
http1
keep-alive:与此对应的,有一个Content-Length属性。
它就像ip包传递的那样,一定要指定长度。这样http收到一系列回复时,才知道什么时候这个请求回完了,再显示出来。
(要记住这样的概念,收到的请求回复不是一下子收到的,而是逐步收到的。写 node 的时候就该意识到)
(如果是请求html/css文件,浏览器是可以做到边收到一部分,边处理这部分的)
http2
简而言之:
-
单域名并发(多路复用)(HTTP/2 通信都在一个连接上完成,这个连接可以承载任意数量的双向数据流)
-
headers压缩
-
服务端推送
-
由文本格式变成了二进制格式(在 应用层(HTTP/2)和传输层(TCP or UDP)之间增加一个二进制分帧层)
这两个回答比较喜欢:
HTTP/2.0 相比1.0有哪些重大改进? - victor yu的回答 - 知乎 https://www.zhihu.com/question/34074946/answer/108588042
HTTP/2.0 相比1.0有哪些重大改进? - Leo Zhang的回答 - 知乎 https://www.zhihu.com/question/34074946/answer/75364178
在没有http2的时候,客户端为了维护长连接,可能需要有自己独特的通信方式。
还有long polling 也就是服务端一直hold住请求不回复 但是会有坑。比如在有代理服务器的情况下(思考:还有什么其他方式呢)
https://www.mnot.net/talks/h2fe/
- 最后因为 HTTP/1 的线头阻塞 (Head of line blocking),使得过去合并多个请求为一个请求成为公共实践,诸如 CSS Sprite、inline image 等其他系列的实践,看似华丽的 HTTP/1 性能优化,实则有一定的开销。
// 这就是一个请求发送失败了,后续会一直堵住?~
- 以及单域名的最大并发,所以才有域名发散 => cdn一般都对应好多域名
我的博客因为都是静态资源,nginx配置很容易。不过要真的在生产环境升http2 还是要有顾虑。
我只能想到的是,推送的时候如果客户端有缓存了,那不就浪费了吗~(https://www.zhihu.com/question/24774343/answer/96586977)
把所有 HTTPS 项目无脑升级成 HTTP/2 会有什么坑吗? - 小爝的回答 - 知乎 https://www.zhihu.com/question/310263956/answer/582342502
webSocket
websocket: WebSocket是基于HTTP1.1的协议,可以简单理解为创建了一条TCP连接
Upgrade: websocket
Connection: Upgrade
p.s. 所以对应的 nginx 配置需要新增:
location / {
#...
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
- 就服务端推送而言,Http/2 与 websocket?
https://stackoverflow.com/questions/28582935/does-http-2-make-websockets-obsolete
http1 的劣势:
请求头太大(200 B 一次 对比 websocket 6 B 一次)。
http2 推送的意义:服务端自动送资源到客户端,但那不是应用程序可以感知的,主要是让浏览器(用户代理)提前缓存静态资源
- 那 websocket 与 SSE 呢?
SSE 可以只管推送,并且似乎使用更简单支持更广泛。主要还是从语义上考虑,「bidirectional data stream」与「publish-subscribe 模式」的区别。前者适合聊天游戏,后者适合 feed 推送。我觉得在业务不确定的情况下,为考虑以后客户端也需要向服务端通信的可能,还是用 websocket 更保险。
以及有个疑问,每个客户端上线,肯定需要告知服务端「它在了」。websocket 天然由客户端发起请求,那 SSE 呢?
https
It uses SSL or TLS to encrypt all communication between a client and a server.
SSL: Secure Sockets Layer
TLS: Transport Layer Security. The successor of SSL
就我个人的理解,TLS 握手的目的是生成一份对称加密的公共秘钥,而如何安全的生成这份秘钥需要做很多事情。
- CA 证书:包含一个私钥和公钥,以及电子签名
- 服务端发送CA签名的证书,里面包括服务端的一份公钥 //避免伪造的服务端【数字证书 —— 安全地发放公钥】
- 客户端经证书验证后,取出公钥,用该公钥加密一个随机数作为对称加密的秘钥,发送给服务端
- 服务端用自己的秘钥解密,获取日后通信的秘钥
Refs:
- https://en.wikipedia.org/wiki/Transport_Layer_Security
- https://www.cloudflare.com/zh-cn/learning/ssl/what-happens-in-a-tls-handshake/
HSTS
是什么?
HTTP Strict Transport Security。
服务器可以强制浏览器使用https通信(使用xxx策略),并且不可忽略不安全的证书提示,(以减少会话劫持风险)。
也就是用户访问https后,只要服务器返回带有strict-transport-security: max-age=31536000; includeSubDomains; preload 的头;
那么以后用户再通过http访问该域名时,浏览器会先返回 307 internal redirect, 并跳转到新的 https 地址。
- 不足一:首次连接仍有风险
用户首次访问某网站是不受HSTS保护的。这是因为首次访问时,浏览器还未收到HSTS,所以仍有可能通过明文HTTP来访问。解决这个不足当前有两种方案,一是浏览器预置HSTS域名列表,Google Chrome、Firefox、Internet Explorer和Microsoft Edge实现了这一方案[11][12]。二是将HSTS信息加入到域名系统记录中。但这需要保证DNS的安全性,也就是需要部署域名系统安全扩展。
见chrome的内置hsts列表: https://src.chromium.org/viewvc/chrome/trunk/src/net/http/transport_security_state_static.json
- 麻烦点:
如果服务器后续修改了配置,又不支持https了,需要用户手动到浏览器清除hsts记忆
http://carlislebear.blogspot.com/2018/06/307-internal-redirect.html
ref: https://zh.wikipedia.org/wiki/HTTP%E4%B8%A5%E6%A0%BC%E4%BC%A0%E8%BE%93%E5%AE%89%E5%85%A8
gzip 附则
https://segmentfault.com/a/1190000012800222
// 好的思考在于:传到 oss 上的文件就是 gzip ,而不是在 nginx 收到请求时再去压缩,能节约服务端的压缩时间