http相关知识总结
今天来总结一下 http 相关知识。
http(HyperText Transfer Protocol):超文本传输协议,是互联网上应用最为广泛的一种网络协议,建立在 TCP 协议上。用于从 WWW 服务器传输超文本到本地浏览器的传输协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。默认端口为 80.
https(Hyper Text Transfer Protocol over Secure Socket Layer):在 http 的基础上,加入了 SSL 来加密传输内容。在后来的发展中,SSL 逐渐演变成 TLS。默认端口未 443。
spdy:是 Google 开发的既有 TCP 的应用层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验。PDY 并不是一种用于替代 HTTP 的协议,而是对 HTTP 协议的增强。新协议的功能包括数据流的多路复用、请求优先级以及 HTTP 报头压缩。
http2.0:即超文本传输协议 2.0,是下一代的 HTTP 协议。HTTP2.0 可以说是 SPDY 的升级版。不会改动 HTTP 的语义,HTTP 方法、状态码、URI 及首部字段,等等这些核心概念上一如往常,却能致力于突破上一代标准的性能限制,改进传输性能,实现低延迟和高吞吐量。
http 的基本优化
影响一个 HTTP 网络请求的因素主要有两个:带宽和延迟。但是目前网络建设已经使宽带得到了极大的提升,我们所需要关心的只是延迟了。
- 浏览器堵塞(HOL blocking):浏览器会因为一些原因阻塞请求。浏览器对于同一个域名,同时只能有 4 个连接(这个根据浏览器内核不同可能会有所差异),超过浏览器最大连接数限制,后续请求就会被阻塞。
- DNS 查询:浏览器需要知道目标服务器的 IP 才能建立连接。将域名解析为 IP 的这个系统就是 DNS。这个通常可以利用 DNS 缓存结果来达到减少这个时间的目的。可以使用
dns-prefetch
来进行预处理。 - 建立连接:HTTP 是基于 TCP 协议的,浏览器最快也要在第三次握手时才能捎带 HTTP 请求报文,达到真正的建立连接,但是这些连接无法复用会导致每次请求都经历三次握手和慢启动。三次握手在高延迟的场景下影响较明显,慢启动则对文件类大请求影响较大。
HTTP1.0 和 HTTP1.1 的一些区别
- 缓存处理,在 HTTP1.0 中主要使用 header 里的 If-Modified-Since,Expires 来做为缓存判断的标准,HTTP1.1 则引入了更多的缓存控制策略例如 Entity tag,If-Unmodified-Since, If-Match, If-None-Match 等更多可供选择的缓存头来控制缓存策略。 缓存的优先级:cache-control > expires > etag > last-modified
- 带宽优化及网络连接的使用,HTTP1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1 则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
- 错误通知的管理,在 HTTP1.1 中新增了 24 个错误状态响应码,如 409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。
- Host 头处理,在 HTTP1.0 中认为每台服务器都绑定一个唯一的 IP 地址,因此,请求消息中的 URL 并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个 IP 地址。HTTP1.1 的请求消息和响应消息都应支持 Host 头域,且请求消息中如果没有 Host 头域会报告一个错误(400 Bad Request)。
- 长连接,HTTP 1.1 支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个 TCP 连接上可以传送多个 HTTP 请求和响应,减少了建立和关闭连接的消耗和延迟,在 HTTP1.1 中默认开启 Connection: keep-alive,一定程度上弥补了 HTTP1.0 每次请求都要创建连接的缺点。
HTTP1.0 和 1.1 现存的一些问题
- 上面提到过的,HTTP1.x 在传输数据时,每次都需要重新建立连接,无疑增加了大量的延迟时间,特别是在移动端更为突出。
- HTTP1.x 在传输数据时,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份,这在一定程度上无法保证数据的安全性。
- HTTP1.x 在使用时,header 里携带的内容过大,在一定程度上增加了传输的成本,并且每次请求 header 基本不怎么变化,尤其在移动端增加用户流量。
- 虽然 HTTP1.x 支持了 keep-alive,来弥补多次创建连接产生的延迟,但是 keep-alive 使用多了同样会给服务端带来大量的性能压力,并且对于单个文件被不断请求的服务(例如图片存放网站),keep-alive 可能会极大的影响性能,因为它在文件被请求之后还保持了不必要的连接很长时间。
HTTPS 与 HTTP 的一些区别
- HTTPS 协议需要到 CA 申请证书,一般免费证书很少,需要交费。
- HTTP 协议运行在 TCP 之上,所有传输的内容都是明文,HTTPS 运行在 SSL/TLS 之上,SSL/TLS 运行在 TCP 之上,所有传输的内容都经过加密的。
- HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
- HTTPS 可以有效的防止运营商劫持,解决了防劫持的一个大问题。
HTTPS 改造
- 安装 CA 证书,一般的证书都是需要收费的,这边推荐一个比较好的购买证书网站:1)Let’s Encrypt,免费,快捷,支持多域名(不是通配符),三条命令即时签署+导出证书。缺点是暂时只有三个月有效期,到期需续签。2Comodo PositiveSSL,收费,但是比较稳定。
- 在购买证书之后,在证书提供的网站上配置自己的域名,将证书下载下来之后,配置自己的 web 服务器,同时进行代码改造。
- HTTPS 降低用户访问速度。SSL 握手,HTTPS 对速度会有一定程度的降低,但是只要经过合理优化和部署,HTTPS 对速度的影响完全可以接受。在很多场景下,HTTPS 速度完全不逊于 HTTP,如果使用 SPDY,HTTPS 的速度甚至还要比 HTTP 快。
- 相对于 HTTPS 降低访问速度,其实更需要关心的是服务器端的 CPU 压力,HTTPS 中大量的密钥算法计算,会消耗大量的 CPU 资源,只有足够的优化,HTTPS 的机器成本才不会明显增加。
使用 SPDY 加快你的网站速度
- 降低延迟,针对 HTTP 高延迟的问题,SPDY 优雅的采取了多路复用(multiplexing)。多路复用通过多个请求 stream 共享一个 tcp 连接的方式,解决了 HOL blocking 的问题,降低了延迟同时提高了带宽的利用率。
- 请求优先级(request prioritization)。多路复用带来一个新的问题是,在连接共享的基础之上有可能会导致关键请求被阻塞。SPDY 允许给每个 request 设置优先级,这样重要的请求就会优先得到响应。比如浏览器加载首页,首页的 html 内容应该优先展示,之后才是各种静态资源文件,脚本文件等加载,这样可以保证用户能第一时间看到网页内容。
- header 压缩。前面提到 HTTP1.x 的 header 很多时候都是重复多余的。选择合适的压缩算法可以减小包的大小和数量。
- 基于 HTTPS 的加密协议传输,大大提高了传输数据的可靠性。
- 服务端推送(server push),采用了 SPDY 的网页,例如我的网页有一个 sytle.css 的请求,在客户端收到 sytle.css 数据的同时,服务端会将 sytle.js 的文件推送给客户端,当客户端再次尝试获取 sytle.js 时就可以直接从缓存中获取到,不用再发请求了。
http2.0 和 SPDY 的区别
- HTTP2.0 支持明文 HTTP 传输,而 SPDY 强制使用 HTTPS。
- HTTP2.0 消息头的压缩算法采用 HPACK,而非 SPDY 采用的 DEFLATE。
http2.0 的新特性
- HTTP2.0 的协议解析决定采用二进制格式,实现方便且健壮。
- 多路复用请求:即连接共享,即每一个 request 都是是用作连接共享机制的。一个 request 对应一个 id,这样一个连接上可以有多个 request,每个连接的 request 可以随机的混杂在一起,接收方可以根据 request 的 id 将 request 再归属到各自不同的服务端请求里面。
- 对请求划分优先级:可以优先处理优先级高的请求。
- 压缩 header:用 encode 压缩 header 大小,并且去除了 header 大量重复的信息,而通讯双方各自缓存一份基础首部表。每次有新增或者修改的首部帧就会被追加到首部帧中。如果请求中不包含首部,那么就自动使用首部表的内容。
- 服务器推送:同 SPDY 一样,HTTP2.0 也具有 server push 功能。
HTTP2.0 的升级改造
- 前文说了 HTTP2.0 其实可以支持非 HTTPS 的,但是现在主流的浏览器像 chrome,firefox 表示还是只支持基于 TLS 部署的 HTTP2.0 协议,所以要想升级成 HTTP2.0 还是先升级 HTTPS 为好。
- 当你的网站已经升级 HTTPS 之后,那么升级 HTTP2.0 就简单很多,如果你使用 NGINX,只要在配置文件中启动相应的协议就可以了,可以参考 NGINX 白皮书,NGINX 配置 HTTP2.0 官方指南。
- 使用了 HTTP2.0 那么,原本的 HTTP1.x 怎么办,这个问题其实不用担心,HTTP2.0 完全兼容 HTTP1.x 的语义,对于不支持 HTTP2.0 的浏览器,NGINX 会自动向下兼容的。
SSL 和 TSL 的区别
SSL 和 TLS 都是加密协议,可在通过网络运行的服务器,机器和应用程序(例如,连接到 Web 服务器的客户端)之间提供身份验证和数据加密。 SSL 是 TLS 的前身。 多年来,新版本的协议已经发布,以解决漏洞,并支持更强大,更安全的密码套件和算法。
SSL 最初是由 Netscape 开发的,最初于 1995 年以 SSL 2.0(1.0 从未向公众发布)登场。 在发现一些漏洞后,版本 2.0 在 1996 年很快被 SSL 3.0 所取代。
TLS 于 1999 年作为 SSL 的新版本推出,并基于 SSL 3.0:这个协议和 SSL 3.0 之间的差异并不明显,但它们足够重要,TLS 1.0 和 SSL 3.0 不会互相影响。
SSL 和 TLS 是否有加密方式的不同?事实上讲,这个问题的答案是肯定的。是您可以对 SSL 2 和 3 的历史版本和 TLS 的 1.1,1.2 或 1.3 版本进行相同的说明。 SSL 和 TLS 都基于相同的协议,但由于版本的不同,SSL 2 与版本 3 不兼容,而 SSL 版本 3 与 TLS 版本 1 不兼容。但是你可以认为 TLS 只是 SSL 4 的别名,他们都是同一个协议。
HTTP 中的状态码(301,302,303,307, 304)
301 永久性转移,302 暂时性转移。
301,302 是 http1.0 的内容,303、307 是 http1.1 的内容。
301 和 302 本来在规范中是不允许重定向时改变请求方法的(将 POST 改为 GET),但是许多浏览器却允许重定向时改变请求方法(这是一种不规范的实现)。因为 post 方法不是幂等,所以 post 操作会不符合用户预期,所以必须跟用户确认要重发后,才能进行第二次 post 请求,而不是 get 请求。
303 就是将 301、302 状态码的处理动作”合法化”了,也就是允许重定向时改变请求方法。此外 303 响应禁止被缓存。大多数的浏览器处理 302 响应时的方式恰恰就是上述规范要求客户端处理 303 响应时应当做的,所以 303 基本用的很少,一般用 302。
307 状态码就是要求 301,302 遵守规定,除了 get 和 head 方法外,其他请求方法必须等到客户端确认后才能跳转,并且请求方式不会改变。
307 还应用于 hsts 跳转。
hsts 全称 HTTP 严格传输安全(HTTP Strict Transport Security,縮寫:HSTS),功能是要求浏览器下次访问该站点时使用 https 来访问,而不再需要先是 http 再转 https。这样可以避免 ssl 剥离攻击,即攻击者在用户使用 http 访问的过程中进行攻击,对服务器冒充自己是用户,在攻击者和服务器中使用 https 访问,在用户和服务器中使用 http 访问。
具体使用方法是在服务器响应头中添加 Strict-Transport-Security,可以设置 max-age
304:协商缓存。
浏览器缓存分为强制缓存和协商缓存,优先读取强制缓存。
强制缓存分为 expires 和 cache-control,而 expires 是一个特定的时间,是比较旧的标准和 cache-control 通常是一个具体的时间长度,比较新,优先级也比较高。
而协商缓存包括 etag 和 last-modified,last-modified 的设置标准是资源的上次修改时间,而 etag 是为了应对资源修改时间可能很频繁的情况出现的,是基于资源的内容计算出来的值,因此优先级也较高。
协商缓存与强制缓存的区别在于强制缓存不需要访问服务器,返回结果是 200,协商缓存需要访问服务器,如果命中缓存的话,返回结果是 304。
HTTP3.0
HTTP3.0 是基于 UDP 开发的,目前的这个协议称为 QUIC。
虽然 HTTP2.0 已经解决了 1.x 时的很多问题,但是目前 2.0 还是存在了不少问题。
- 建立连接时间长(本质上是 TCP 的问题)
- 队头阻塞问题
- 移动互联网领域表现不佳(弱网环境)
队头阻塞问题
HTTP2.0 的多路复用主要解决了 HTTP 层的队头堵塞,但是在 TCP 层还是依旧存在,TCP 协议在收到数据包之后,这部分数据可能是乱序到达的,但是 TCP 必须将所有数据收集排序整合后给上层使用,如果其中某个包丢失了,就必须等待重传,从而出现某个丢包数据阻塞整个连接的数据使用。
QUIC 协议是基于 UDP 协议实现的,在一条链接上可以有多个流,流与流之间是互不影响的,当一个流出现丢包影响范围非常小,从而解决队头阻塞问题。
0RTT 建链
衡量网络建链的常用指标是 RTT Round-Trip Time,也就是数据包一来一回的时间消耗。RTT 包括三部分:往返传播时延、网络设备内排队时延、应用程序数据处理时延。一般来说 HTTPS 协议要建立完整链接包括:TCP 握手和 TLS 握手,总计需要至少 2-3 个 RTT,普通的 HTTP 协议也需要至少 1 个 RTT 才可以完成握手。然而,QUIC 协议可以实现在第一个包就可以包含有效的应用数据,从而实现 0RTT,但这也是有条件的,需要在双方完成首次连接后。
简单来说,基于 TCP 协议和 TLS 协议的 HTTP2.0 在真正发送数据包之前需要花费一些时间来完成握手和加密协商,完成之后才可以真正传输业务数据。但是 QUIC 则第一个数据包就可以发业务数据,从而在连接延时有很大优势,可以节约数百毫秒的时间。
连接迁移
TCP 协议使用五元组来表示一条唯一的连接,当我们从 4G 环境切换到 wifi 环境时,手机的 IP 地址就会发生变化,这时必须创建新的 TCP 连接才能继续传输数据。
QUIC 协议基于 UDP 实现摒弃了五元组的概念,使用 64 位的随机数作为连接的 ID,并使用该 ID 表示连接。
基于 QUIC 协议之下,我们在日常 wifi 和 4G 切换时,或者不同基站之间切换都不会重连,从而提高业务层的体验。
结尾
相关链接: