# 关于 Http
关于 tcp握手/挥手 相关内容在 从输入URL到页面加载过程
# 从 http1.0 到 http1.1
在浏览器中,越来越多的使用更多的图片和更多的懒加载组件,然后会导致页面加载时会加载很多的几kb文件,
因此 http 经过了好几代的更新。
从古老的 http1.0 开始,它存在的以下的问题
- 在http1.0中,发送一次请求时,需要等待服务端响应了才可以继续发送请求。
- 连接方式是短链接
为了解决上述 http1.0 的问题,出现了 http 1.1,它主要做了以下改动
- 持久连接:出现了默认长连接方式
keep-alive
- 请求管道化:发送一次请求时,不需要等待服务端响应了就可以发送请求了。
- 理想情况中 HTTP 请求管道化(流水线)启动时,后续请求都可以不用等待第一个请求的成功响应就被发送。
- 然而HTTP管道化,很难在现有网络中有很多老旧的软件与现代版本的软件共存
- 增加缓存处理:新的字段如
cache-control
- 增加Host字段、支持断点传输等
keep-alive
:在规定时间内,同一域名多次请求数据,只建立一次HTTP请求,后续请求可复用之前的连接通道。该规定时间默认为2小时
,可以通过 Apache
或者 nginx
配置。
但是,http1.1的问题依然存在
- 在 http1.1中,基于请求-响应的模型,在同一个 TCP 长连接中,前面的请求没有得到响应,后面的请求就会被阻塞,服务器回送数据给客户端的时候,客户端需要按照响应的顺序来一一接收。也就是线头阻塞。
- 在 http1.1 中无论是请求还是响应都是基于文本的,在数据传输的过程中服务器并不知道字符的顺序。所以:keep-alive 对于单文件的传输是block级的,数据必须按顺序传输,不能并行。
# 从 http1.1 到 http2
2015年 出现了 http2, 它在 http1.1 语法和底层传输协议之间增加了一个新的中间层,而没有从根本上修改它,即它是建立在经过验证的机制之上,这个中间层就是帧机制。它引入 二进制数据帧
和 流
的概念,利用帧对数据进行顺序标识,利用流进行数据并行传输
主要改进点
- 头部压缩 -> 减少体积
- 采用
HPACK
压缩:利用服务器和客户端之间建立哈希表的映射,传递索引来精简和复用请求头部
- 采用
- 二进制 + 分帧传输 -> 减少体积 + 提高安全性
- 由于 HTTP 的明文传输解析太过复杂(比如
\n
到底是换行还是字符串?),而且并不安全。所以,采用二进制进行传输 - 将数据以流的形式进行传输,并将请求和响应数据分割成更小的帧,而多个帧之间可以乱序发送,根据帧首部的流标识来重新组装。
- 由于 HTTP 的明文传输解析太过复杂(比如
- 多路复用 -> 解决队头阻塞
- 只需要占用一个 TCP 连接
- 服务器推送
其他改动点
- http2.0 只用于 https
# 关于 HTTPS
HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer 超文本传输安全协议)
HTTPS在传统的HTTP和TCP之间加了一层用于加密解密的SSL/TLS层
(安全套接层Secure Sockets Layer/安全传输层Transport Layer Security)层。
PS: 当SSL
发展到第三大版本时才被标准版,成为 TLS
。即:TLS1.0 = SSL3.1
HTTPS解决的问题
- 信息加密传输:第三方无法窃听;
- 校验机制:一旦被篡改,通信双方会立刻发现;
- 身份证书:防止身份被冒充。
HTTPS在传输数据阶段依然使用对称加密,但是对称加密的密钥我们采用非对称加密来传输,使用HTTPS必须要有一套自己的数字证书(包含公钥和私钥)。
HTTPS加密过程:
- 客户端请求服务器获取
证书公钥
(第三版返回的是数字证书,之前是直接返回的公钥) - 客户端(SSL/TLS)解析证书(无效会弹出警告)
- 生成随机值
- 用
公钥加密
随机值生成密钥 - 客户端将
秘钥
发送给服务器 - 服务端用
私钥
解密秘钥
得到随机值 将信息和随机值混合在一起
进行对称加密- 将加密的内容发送给客户端
- 客户端用
秘钥
解密信息
加密过程使用了对称加密和非对称加密。
- 对称加密: 客户端和服务端采用相同的密钥经行加密
encrypt(明文,秘钥) = 密文 decrypt(密文,秘钥) = 明文
- 非对称加密:客户端通过公钥加密。服务端通过私钥解密
encrypt(明文,公钥) = 密文 decrypt(密文,私钥) = 明文
因为TLS握手的过程中采用了非对称加密,客户端本身不知道服务器的秘钥,这样通信就不会被中间人劫持。此外这一步服务端还提供了证书,并且可能要求客户端提供证书。关于证书下文会提到,只要有了证书,就能保证和你通信的对方是真实的,而不是别人伪造的。
那然后如何验证证书?
- 客户端获取到了站点证书,拿到了站点的公钥
- 客户端找到其站点证书颁发者的信息
站点证书的颁发者
验证服务端站点
是否可信- 往上回溯,找到
根证书颁发者
- 通过
根证书颁发者
一步步验证站点证书颁布者
是否可信
附:
- HTTPS默认使用443端口,而HTTP默认使用80端口。
- TLS就是从SSL发展而来的,只是SSL发展到3.0版本后改成了TLS
- 第一次请求中TLS握手的代价很大
- 后续的请求会共用第一次请求的协商结果
参考:
# http 和 ajax 的区别
ajax:基于 xmlHttpRequest
http:基于 httpRequest
ps:ajax 请求头会多一个 x-requested-with
参数,值为 XMLHttpRequest
# QUIC
Google 研发了一种以 UDP
为基础,能提供更可靠更高效的传输协议 QUIC
,目前为止浏览器支持很有限。
可能成为 http3.0
# TCP慢启动
最初的TCP的实现方式是,在连接建立成功后便会向网络中发送大尺寸的数据包,假如网络出现问题,很多这样的大包会积攒在路由器上,很容易导致网络中路由器缓存空间耗尽,从而发生拥塞。
因此现在的TCP协议规定了,新建立的连接不能够一开始就发送大尺寸的数据包,而只能从一个小尺寸的包开始发送,在发送和数据被对方确认的过程中去计算对方的接收速度,来逐步增加每次发送的数据量(最后到达一个稳定的值,进入高速传输阶段。相应的,慢启动过程中,TCP通道处在低速传输阶段),以避免上述现象的发生。这个策略就是慢启动。
# 关于cookie
首先 http1.x 是无状态的,既然是无状态的那么就存在会话状态问题,比如:登录信息在客户端的留存。因此就出现了 cookie。
cookie 的属性:
- Expires: 过期时间(缺省则浏览器关闭时清除)
- Max-Age:失效前需要建立的毫秒数(优先级大于Expires)
- Domain:指定的域名(这个域名不可跨域指定)
- Path:指定path路径
- Secure:只能通过 https 传递
- HttpOnly:只能通过在http响应头中添加
Set-Cookie
时才能设置cookie,通过document.cookie
设置无效 - SameSite:在跨站请求时是否发送cookie
- None:无论是否跨站都会发送 cookie
- Lax:允许导航到目标网址的
get请求
发送cookie - Strict:最严格,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。
ps:由于2020年2月chrome-v80更改了SameSite
属性,默认屏蔽了第三方cookie(从 None
改为 Lax
),用以预防CSRF
攻击,因此也导致很多大厂的跨域交互出现了问题,这时,网站可以选择显式关闭SameSite属性,将其设为None。前提是必须同时设置Secure
属性,否则无效。