HTTP 网络协议
HTTP(Hypertext Transfer Protocol)是超文本传输协议,是互联网上应用最为广泛的协议。如建立客户端和服务端之间的通讯。
目前 HTTP 1.1 为互联中的主要协议,而 HTTP/2 是 HTTP 协议自 1999 年 HTTP 1.1 发布后的首个更新,简称h2。
2015年底 Google Chrome、Mozilla Firefox、Microsoft Edge和Opera已支持HTTP/2,并默认启用。
HTTP 消息
HTTP 报文/消息分为请求(由客户端发送来触发服务器上的一个动作)和响应(来自服务器的应答),由采用ASCII编码的多行文本构成。
编码
HTTP/1.x 的请求和响应报文,都是由起始行(start line,用于描述要执行的请求,或对应的状态码),首部(HTTP headers,可选的键值对,用于描述请求或响应的内容,如:Content-Type)、和正文(body,可选的,报文真正的内容,如:查询字符串、响应的相关文档)组成,各部分之间以文本换行符(empty line)分隔。
HTTP/2 将请求和响应数据分割为更小的帧,并且它们采用二进制编码。
多路复用
HTTP 1.x 中,如果想并发多个请求,必须使用多个 TCP 链接。浏览器为了控制资源,会对单个域名有 6-8 的个数限制,超过限制的请求会被挂起等待了一段时间。
HTTP/2中:
- 同域名下所有通信都在单个连接上完成(合并在同一 TCP 连接内)
- 单个连接可以承载任意数量的双向数据流 Stream。
- 数据流以消息 Message 的形式发送,而消息又由一个或多个帧 Frame 组成,多个帧之间可以乱序发送,因为根据帧首部的流标识可以重新组装。
实践表明,相比HTTP/1.1,新页面加载可以加快11.81% 到 47.7%
头部压缩
HTTP 每一次通信都会携带一组头部,用于描述这次通信的的资源、浏览器属性、cookie 等。
HTTP/2 对消息头采用 HPACK算法(专为http2头部设计的压缩格式)进行压缩传输,而 HTTP/1.x 每次请求都会携带大量冗余头信息,浪费带宽资源。
具体实现:
- 在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对;
- 首部表在 HTTP/2 的连接存续期内始终存在,由客户端和服务器共同渐进地更新;
- 每个新的首部键-值对要么被追加到当前表的末尾,要么替换表中之前的值。
服务端推送(Server Push)
服务端向客户端发送比客户端请求更多的数据。这允许服务器直接提供浏览器渲染页面所需资源,而无须浏览器在收到、解析页面后再提起一轮请求,节约了加载时间。
安全
HTTP/2设计本身允许非加密的 http 协议,但多数客户端开发者声明只支持通过 TLS 加密的h2协议,使得经TLS加密的HTTP/2(即h2)成为了事实上的强制标准。
HTTP Cache 缓存
HTTP 的缓存行为由 request header 和 response header 组合起来控制的。理想情况下,web app 控制请求头,web server 控制响应头。
好处:
- 缓解服务器内存消耗、减少程序执行压力,提升服务端的整体性能
- 提升资源加载速度、减少某些资源占有系统资源的时间
- 降低带宽的损耗、减少网络拥塞
- 提升web站点响应速度
缓存分为私有缓存和共享缓存。
私有缓存:用于单独用户,如浏览器缓存、私密信息。cache-control: private
共享缓存:服务于多个用户,如ISP或公司架设的web代理服务器(很多电脑通过一台电脑访问公网)缓存图片、视频。cache-control: public
Request headers
影响检测新鲜度的请求头,如 If-None-Match
、 If-Modified-Since
,基于对缓存里当前值的理解,会自动添加到请求头里。因此保持 default 行为即可,浏览器会帮我们管理 http caching
缓存控制
对于前端开发者来说,关于缓存资源的问题,都仅仅针对GET请求。而对于POST/DELETE/PUT这类行为性操作通常不做任何缓存。
HTTP通过缓存将服务器资源的副本保留一段时间,这段时间称为新鲜度限值。这在一段时间内请求相同资源不会再通过服务器。
HTTP协议中 Cache-Control
和 Expires
可以用来设置新鲜度的限值,前者是 HTTP1.1 中新增的响应头,后者是 HTTP1.0 中的响应头。二者所做的事时都是相同的,但由于 Cache-Control 使用的是相对时间,而 Expires 可能存在客户端与服务器端时间不一样的问题,所以 Cache-Control更为准确。
Cache-Control 不仅仅可以在响应头中设置,还可以在请求头中设置。可能设置的属性值有:
- private【私有缓存】浏览器可以缓存文件,用于单独用户。对一些用户信息敏感的资源,通常需要设置为 private。
- public【共享缓存】指定响应可以在代理缓存中被缓存,于是可以被多用户共享。如果没有明确指定 private,则默认为 public。
- no-store【禁止进行缓存】告诉浏览器和其他中间缓存(如CDN)不存储任何版本的文件。也就是说每次用户请求资源时,都会向服务器发送一个请求,每次都会下载完整的资源。通常用于机密性资源,如访问银行业务。
- no-cache【强制确认缓存】表示必须先与服务器确认资源是否被更改过(依靠 If-None-Match 和 Etag),然后再决定是否使用本地缓存。针对 unversioned URLs
- max-age【缓存过期机制】(单位为s)指定设置缓存最大的有效时间,定义的是时间长短。当浏览器向服务器发送请求后,在 max-age 这段时间里浏览器就不会再向服务器发送请求了。最大值 31536000,即1年。针对含有版本信息的 URL
- must-revalidate【缓存验证确认】
缓存的流程控制
http请求-》是否有缓存?
-》如果有缓存-》是否过期?判断响应头中的Cache-Control
和Expires
-》没过期-》使用缓存-》页面展示。【强制缓存】
-》过期-》资源是否有Etag
/Last-Modified
?
-》没有-》向服务器发起请求,状态码200-》服务器返回资源,响应头添加Etag
/Last-Modified
-》有-》向服务器发起请求,请求头带上If-None-Match
/If-Modified-Since
-》服务器判断缓存是否过期
-》已过期,状态码200-》服务器返回资源,响应头添加Etag
/Last-Modified
-》页面展示
-》没过期,状态码304-》读取缓存-》页面展示。【协商缓存】
-》没有缓存-》向服务器发起请求,状态码200-》服务器返回资源,响应头添加Etag
/Last-Modified
-》页面展示
如何更新缓存
浏览器或代理缓存中缓存的资源过期,并不意味着它和原始服务器上的资源有实际的差异,仅仅意味着到了要进行核对的时间了,这种情况被称为服务器再验证。
如果资源发生变化,则需要取得新的资源,并在缓存中替换旧资源。如果资源没有发生变化,缓存只需要获取新的响应头,和一个新的过期时间,对缓存中的资源过期时间进行更新即可。
HTTP1.1 推荐使用的验证方式是 If-None-Match
/ Etag
分别对应 Request Headers 和 Response Headers,在 HTTP1.0 中则使用 If-Modified-Since
/ Last-Modified
.
当用于更新缓存时,cache 使用已缓存message的 Last-Modified
字段的值生成 If-Modified-Since
字段的值。
- Etag:当浏览器找到一个已过期的缓存响应时,它可以向服务器发送一个token(通常是文件内容的hash)以检测文件是否已更改。如果服务器返回相同的token,则说明文件相同,则无需下载。
- Last-Modified:作用同 Etag,只不过是 time-based 策略决定资源是否改变,而后者是 content-base 策略。推荐使用 Etag 更为准确。
以下情况必须忽略 If-Modified-Since
:
- 如果请求中包含一个
If-None-Match
- 如果 If-Modified-Since = HTTP-date 中,值不是一个有效的 HTTP-date
- 如果请求既不是 GET 也不是 HEAD
资源一旦被浏览器缓存,浏览器就会一直使用 cached 版本的资源除非过期,或者用户主动清除了浏览器缓存。因此想要强制用户下载最新资源,通过给文件名加hash或版本号,改变资源 URL,实现通知浏览器更新已缓存的文件。
Conditional request
Conditional requests are HTTP requests [RFC7231] that include one or more header fields indicating a precondition to be tested before applying the method semantics to the target resource.
条件的请求是指包含一个或多个头字段,它们指示在应用到目标资源之前有需要测试的先决条件的 HTTP 请求。
常见状态码
400 - Bad Request,客户端传入参数的错误,如必选参数没有传入等 404 - Not Found,接口要访问的资源不存在,一般是URL或URL的参数错误 405 - Method Not Allowed,接口访问的 Method 不正确,比如应该使用 GET 的接口使用了 POST 方法访问等 500 - Internal Server Error,其它类型的错误默认都会返回500
更全的解释看这里
HTTPS
HTTPS并非是应用层的一种新协议,而是 HTTP 通信接口部分用 SSL/TLS 协议代替而已。
它就是 HTTP 只是对传输数据进行了加密。
HTTP报文使用明文(指未经过加密的报文)方式发送,缺陷是导致信息窃听/数据泄露(通过网络的嗅探设备还原http内容)、数据篡改(没有任何办法确认,发出的请求/响应和接收到的请求/响应是前后相同的)、流量劫持、钓鱼欺诈(请求和响应不会对通信方进行确认,任何人都可以伪造虚假服务器欺骗用户)等安全问题的重要原因。
HTTPS标准端口443,HTTP标准端口80;
要进行HTTPS通信,证书是必不可少的,对网站服务器进行真实身份认证。而使用的证书必须向认证机构(CA)购买。
其次,HTTPS普遍认为性能消耗要大于HTTP,因为与纯文本通信相比,加密通信会消耗更多的CPU及内存资源。如果每次通信都加密,会消耗相当多的资源,平摊到一台计算机上时,能够处理的请求数量必定也会随之减少。但事实并非如此,用户可以通过性能优化、把证书部署在SLB或CDN,来解决此问题。
网站切换到https的域名,谷歌浏览器访问仍然提示“不安全”。打开开发者工具“Security”栏,在Overview里面看到:This page is not secure. Resources - mixed content,This page includes HTTP resources. View ** requests in Network Panel。
点击最后那句话的链接,在“Network”栏直接看到了所有http加载的资源。
SSL vs TLS
Secure Socket Layer,由 NETSCAPE 发明,其第一版并没有 release。1995年发行了v2,之后发布了v3。1999年 NETSCAPE 把SSL协议的控制权给了 IETF(Internet Engineering Task Force,互联网工程任务组),该组织 renamed SLL to TLS(Transport Layer Security),并在1999年发布了 TLS 1.0。直到2015年,SSL 3.0 被官宣 deprecated。2018年 TLS 1.3 通过,目前浏览器支持率 83.6%,而 TLS 的支持率在 98%。
使用https加载的图片protocol却是http/1.1?
h2 vs https
HTTP/2 is only supported over TLS (HTTPS).
Chrome浏览器查看Protocol
在“Network”栏下,Name、Status、Domain…那表格头鼠标右键点击,在打开的菜单栏里勾选“Protocol”即可。