HTTP
初识 HTTP
HTTP 位于计算机网络的哪一层
ISO(国际标准化组织)为了更好的使网络应用得到普及,推出了 OSI 参考模型。
应用层
最靠近用户的一层,为计算机用户提供应用接口,也为用户直接提供各种网络服务。应用层常见的网络服务协议有:HTTP,HTTPS,FTP,POP3,SMTP,DNS 等。
什么是 HTTP 协议
- Hyper Text Transfer Protocol 超文本传输协议
- 应用层协议,基于 TCP
- 请求响应 模式
- 简单可扩展
- 无状态
协议分析
HTTP 发展
HTTP 0.9 单行协议
- 仅支持 GET 请求,响应 html 文档
HTTP 1.0 构建可扩展性
- 增加 Header、状态码
- 允许多种文档类型(html、css)
- ...
HTTP 1.1 标准化协议
- 链接复用
- 缓存
- 内容协商
- ...
HTTP 2 更优异的表现
- 二进制协议
- 压缩 header
- 服务器推送
- ...
HTTP 3 ...
HTTP 1.0 和 HTTP 1.1
连接方面
- http 1.0 默认使用非持久连接(浏览器每次发起HTTP请求都要与服务器建立一个TCP连接,服务器完成请求处理之后就会立即断开这个 TCP 连接)
- http 1.1 默认使用持久连接,通过持久连接来使多个 http 请求复用同一个 TCP 连接,以此来避免使用非持久连接时每次需要建立连接的时延。
管道网络传输
HTTP/1.1 采用了长连接的方式,使得管道(pipeline)网络传输成为了可能。
管道网络传输是指:可以在同一个 TCP 连接中,客户端发送多个请求,只要第一个请求发送出去,不必等待其响应,就可以发送第二个请求,以此减少整体的响应时间。
但是服务器还是按照顺序回应请求,如果前面的回应特别慢,后面就会有许多请求排队,造成队头阻塞。
队头阻塞
HTTP 传输的报文必须是一发一收,任务队列的串行执行可能会因为队首阻塞后面的请求。
队头阻塞的解决方案
(1)并发连接:对于一个域名允许分配多个长连接,相当于增加了任务队列
(2)域名分片:将域名分出许多二级域名,它们都指向同样的一台服务器,能够并发的长连接数变多。
资源请求方面
-
http 1.0 存在浪费带宽的现象:
- 客户端只是需要某个对象的一部分,而服务器将整个对象发送过来
- 不支持断点续传
-
http 1.1 在请求头引入了 range 头域,它允许只请求资源的某个部分,返回码是 206(Partial Content),这样就方便开发者自由的选择以充分利用带宽和连接
缓存方面
- http 1.0 主要使用 header 里面的 If-Modified-Since、Expires 来作为缓存判断的标准
- http 1.1 引入更多的缓存控制策略,如 Etag、If-Unmodified-Since、If-Match、If-None-Match
其他方面
- http 1.1 中新增了 host 字段,用来指定服务器的域名。http 1.0 中认为每台服务器都绑定一个唯一的 IP 地址,因此请求消息中 URL 并没有传递主机名。但随着虚拟主机计数的发展,在一台物理服务器上可以存在多个虚拟主机,并且它们共享了一个 IP 地址。因此有了 host 字段,就可以将请求发往同一台服务器的不同网站。
- http 1.1 新增了很多请求方法:PUT、DELETE、OPTIONS、TRACE、CONNECT 等
HTTP 1.1 和 HTTP 2.0
协议内容
- 在 HTTP/1.1 版中,报文的头信息必须是文本(ASCII 编码),数据体可以是文本,也可以是二进制。
- HTTP/2 是一个彻底的二进制协议,头信息和数据体都是二进制的,统称为“帧”,可以分为头信息帧和数据帧。帧的概念是实现多路复用的基础。
多路复用
HTTP/2 实现了多路复用,HTTP/2 仍然复用 TCP 连接,但是在一个连接里,客户端和服务器都可以同时发送多个请求或回应,而且不用按顺序一一发送,这样就避免了“队头堵塞”的问题。
数据流
HTTP/2 使用了数据流的概念,因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的请求。因此,必须对数据包进行标记,指出它属于哪个请求。
HTTP/2 将每个请求或回应的所有数据包,称为一个数据流。每个数据流都有一个独一无二的编号,数据包发送时,都必须标记数据流 ID,用来区分它属于哪个数据流。
头信息压缩
-
由于 HTTP 1.1 协议不带状态,每次请求都必须附上所有信息,因此很多请求的字段可能重复,比如 Cookie 和 User-Agent,浪费带宽也影响速度。
-
HTTP/2 实现了头信息压缩
- 头信息使用 gzip 或 compress 压缩后再发送
- 客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样的字段了,只发送索引号,这样可以提高速度
服务器推送
HTTP/2 允许服务器未经请求,主动向客户端发送资源,即服务器推送。
使用服务器推送提前给客户端推送必要的资源,相对减少一些延迟时间。
注意:主动推送的是静态资源,不同于 WebSocket 以及使用 SSE 等方式向客户端发送即使数据的推送。
HTTP 的请求报文
HTTP 的请求报文有 4 部分:
- 请求行
- 请求头部
- 空行
- 请求体
其中:
- 请求行
包括:请求方法字段、URL 字段、HTTP 协议版本字段,分别用空格分割
例如 GET /index.html HTTP/1.1
- 请求头部
请求头部由关键字/值对组成,每行一对,键值之间用英文逗号 : 分割
- User-Agent:产生请求的代理类型
- Accept:客户端可识别的内容列表
- Host:请求的主机名,允许多个域名同处一个 IP地址,即虚拟主机
- 请求体
POST,PUT 等请求携带的数据
HTTP 响应报文
HTTP 响应报文有 4 部分:
- 响应行
- 响应头
- 空行
- 响应体
- 响应行
包括:网络协议版本,状态码和状态码的原因短语,用空格分割
例如:HTTP/1.1 200 OK
- 响应头:响应头部组成
- 响应体:服务器响应的数据
常见的 HTTP 请求方法
- GET:向服务器获取数据
- POST:将实体提交到指定的资源,通常会造成服务器资源的修改
- PUT:上传文件,或更新数据
- DELETE:删除服务器上的对象
- HEAD:获取报文首部,与 GET 相比,不返回报文主体部分
- OPTIONS:询问支持的请求方法,用来跨域请求
- CONNECT:要求在与代理服务器通信时建立隧道,使用隧道进行 TCP 通信
- TRACE:回显服务器收到的请求,主要用于测试或诊断
常用 HTTP 状态码简介
-
2XX 成功
- 200 OK,表示从客户端发来的请求再服务器端被正确处理
- 204 No Content,表示请求成功,但响应报文不含实体的主体部分
- 205 Reset Content,表示请求成功,但响应报文不含实体的主体部分,但是与 204 响应不同在于 要求请求方重置内容
- 206 Partial Content,表示进行了范围请求
-
3XX 重定向
- 301 moved permanently,永久性重定向,表示资源已被分配到新的 URL
- 302 found,临时重定向,表示资源临时被分配了新的 URL
- 303 see other,表示资源存在着另一个 URL,应使用 GET 方法获取资源
- 304 not modified,表示服务器允许访问资源,但因发生请求未满足条件的情况
- 307 temporary redirect,临时重定向,和 302 含义类似,但是期望客户端保持请求方法不变向新的地址发送请求
-
4XX 客户端错误
- 400 bad request,请求报文存在语法错误
- 401 unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息
- 403 forbidden,表示对请求资源的访问被服务器拒绝
- 404 not found,表示在服务器上没有找到请求的资源
-
5XX 服务器错误
- 500 internal server error,表示服务器在执行请求时发生了错误
- 501 Not Implemented,表示服务器不支持当前请求所需要的某个功能
- 503 service unavailable,表示服务器暂时处于超负载或正在停机维护,无法处理请求
RESTful API
Representational State Transfer
- 每一个 URI 代表一种资源
- 客户端和服务器之间,传递这种资源的某种表现层
- 客户端通过 HTTP method,对服务器端资源进行操作,实现“表现层状态转化”
常见的 HTTP 请求头和响应头
HTTP Request Header 请求头:
- Accept:浏览器能够处理的内容类型
- Accept-Charset:浏览器能够显示的字符集
- Accept-Encoding:浏览器能够处理的压缩编码
- Accept-Language:浏览器当前设置的语言
- Authorization:身份验证信息
- Connect:浏览器与服务器之间连接的类型
- Cookie:当前页面设置的任何 Cookie
- Host:指明了请求将要发送到的服务器主机名和端口号
- Referer:发出请求的页面的URL
- User-Agent:浏览器的用户代理字符串
HTTP Responses Header 响应头:
-
Date:消息发送的时间,描述格式由 rfc822 定义
-
server:服务器名称
-
Connection:浏览器与服务器之间连接的类型
-
Cache-Control:控制 HTTP 缓存
-
Content-Type:表示后面的文档属于什么类型
-
(默认值)application/x-www-form-urlencoded:浏览器原生表单
按照 key1=val1&key2=val2 的方式编码。
- POST 将数据放在 body 里面
- GET 将数据放在 url 里
-
multipart/form-data: 常见的 POST 提交方式,通常用于上传文件
会设置一个
boundary 分割字符串 -
application/json: 服务器消息主题是序列化后的 JSON 字符串
-
text/xml: 通过 XML 格式提交数据
-
-
Set-Cookie:返回给客户端的 Cookie
HTTP 的缓存
HTTP 缓存主要是通过请求和响应报文头中的对应的 Header 信息,来控制缓存的策略。
HTTP 缓存可以缩短网页请求资源的举例,减少延迟,节省网络流量,并且由于缓存文件可以重复利用,因此还能降低网络符合,提高客户端响应。
根据是否需要重新向服务器发起请求,可分为:
- (不需要发送请求)强缓存
- (需要发送请求)协商缓存
强缓存
也叫强制缓存
当命中强缓存时,客户端不会再请求服务器,直接从缓存中读取内容,并返回 HTTP 状态码 200。
强制缓存,在响应头由 Expires、Cache-Control 和 Pragma 控制。
优先级:Pragma > Cache-Control > Expires
Expires
HTTP1.0 的属性,值为服务器返回的过期时间。
浏览器再次加载资源时,如果在这个过期时间内,则命中强缓存。
缺点是如果服务端和客户端时间不一致,会导致命中误差。
Cache-Control
HTTP1.1 属性,有以下常用的属性:
-
no-store:禁止缓存
-
no-cache:不使用强缓存,每次需向服务器验证缓存是否失效
-
private/public:
- private 指单个用户
- public 指可以被任何中间人(代理服务器、CDN等)缓存
-
max-age:距离请求发起的时间的秒数
-
must-revalidate:在缓存过期前可以使用,过期后必须向服务器验证
Cache-Control: max-age=0 和 no-cache 有什么不同?
语义上不同。
max-age=0 告诉客户端资源的缓存到期,应该向服务器验证缓存的有效性。
no-cache 告诉客户端使用缓存前必须向服务器验证缓存的有效性。
max-age 和 expires 共存时,max-age 的优先级更高。
pragma
HTTP1.0 属性,那时候 Cache-Control 还没有出来
效果和 cahe-control 的 no-cache 一致。
强缓存的资源存储位置
| 状态 | Network - Size | 含义 |
|---|---|---|
| 200 | from memory cache | 不请求网络资源,资源在内存。一般是脚本、字体、图片,浏览器关闭,数据将被释放 |
| 200 | from disk cache | 请求网络资源,资源在磁盘。一般是 css 等,关闭浏览器数据还存在。 |
| 200 | 资源大小 | 从服务器下载最新资源 |
| 304 | 报文大小 | 请求服务端发现资源未更新,使用本地资源 |
为什么同一个资源有时是 from memory cache,有时是 from disk cache?
Chrom 会根据本地内存的使用率来决定缓存存放位置,如果内存使用率很高,则会放在磁盘中。
协商缓存
向服务器发送请求,服务器会根据请求头的一些参数来判断是否命中协商缓存。
如果命中,则返回 304 状态码并带上新的响应头通知浏览器从缓存中读取资源。
协商缓存,响应头中有两个字段标记规则
Last-Modified / If-Modified-Since
-
Last-Modified:(浏览器第一个请求资源,服务器响应头字段)值是资源文件最后一次更改时间,精确到秒 - 下一次发送请求时,请求头里的
If-Modified-Since 就是之前的 Last-Modified - 服务器根据最后修改时间判断命中,如果命中,状态码为304且不返回资源,不返回 Last-Modified
Etag / If-None-Match
Etag 的校验优先级高于 Last-Modified
-
Etag 是加载资源时,服务器返回的响应头字段。值是对资源的唯一标记,一个 hash 码 - 浏览器在下一次加载资源向服务器发送请求时,会将上一次返回的 Etag 值放到请求头里的
If-None-Match - 服务器接收到 If-None-Match 的值后,会拿来根资源文件的 Etag 值作比较,如果相同,则表示资源文件没有发生改变,命中协商缓存。
在精确度上,Etag 要优于 Last-Modified,因为后者的精确度是秒,而前者是资源的哈希值。
在性能上,Etag 要劣于 Last-Modified,因为需要通过算法计算 hash 值。
在优先级上,服务器校验优先考虑 Etag。
用户行为对缓存的影响
| 用户操作 | Expires/Cache-Control | Last-Modified/Etag |
|---|---|---|
| 地址栏回车、页面链接跳转、新开窗口、前进后退 | 有效 | 有效 |
| F5刷新 | 无效 | 有效 |
| Ctrl + F5 强制刷新 | 无效 | 无效 |
勘误:图中协商缓存命中后返回的状态码应该是 304 而不是 302
不设置缓存的方法
- 在 html 文件设置 meta
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache, must-revalidate">
<meta http-equiv="expires" content="Wed, 26 Feb 1997 00:00:00 GMT">
- 服务端响应添加
Cache-Control: no-cache, must-revalidate - 修改请求头
If-modified-since:0 或If-none-match - 请求 url 后增加时间戳
- 服务端设置
Cache-Control: private 指令,防止代理服务器缓存资源
Cookie
解决 HTTP 无连接无状态导致的身份识别问题
常见字段
| 字段=值 | 描述 |
|---|---|
| Name=value | 各种Cookie的名称和值 |
| Expires=Date | Cookie的有效期,缺省时Cookie仅在浏览器关闭之前有效 |
| Path=Path | 限制指定Cookie的发送范围的文件目录,默认当前 |
| Domain=domain | 限制Cookie生效的域名,默认为创建Cookie的服务域名 |
| secure | 仅在HTTPS安全连接时,才可以发送Cookie |
| HttpOnly | JS 脚本无法获得 Cookie |
| SameSite=[None|Strict|Lax] | None 同站、跨站请求都可发送;Strict 仅在同站发送;Lax 允许于顶级导航一起发送,并将与第三方网站发起的 GET 请求一起发送 |
HTTPS
HTTP 和 HTTPS 协议的区别
-
HTTPS 协议需要 CA 证书,费用较高;HTTP 协议不需要
-
HTTP 协议是超文本传输协议,信息是明文传输的,HTTPS 是具有安全性的 SSL 加密传输协议
- HTTP 不验证对方的身份,可能被劫持、伪装,无法证明报文的完整性(可能被篡改)
-
使用不同的连接方式,端口也不同,HTTP 协议默认端口是80,HTTPS 协议默认端口是 443
-
HTTP 协议连接很简单,是无状态的;HTTPS 协议是具有 SSL 和 HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 更加安全
HTTPS 是如何保证安全的
对称加密:通信的双方使用同一个密钥进行加解密
- 简单,性能好
- 无法解决首次把密钥发送给对方的问题,很容易被黑客拦截密钥
非对称加密:
- 使用私钥和公钥,组成密钥对
- 用私钥加密的数据,只有对应的公钥才能解密;用公钥加密的数据,只有对应的私钥才能解密
- 通信双方手里都有一套自己的密钥对,通信之前双方会把自己的公钥发送给对方
- 然后用收到的公钥加密数据,响应给对方,等到了对方那里,对方用自己的私钥进行解密
- 安全性能更高,但是速度比较慢,影响性能
HTTPS 使用非对称加密,但是这样存在中间人问题:
如果此时再客户端和服务器之间存在一个中间人,这个人把双方通信互发的公钥换成自己的公钥,则中间人可以轻松解密通信双方所发送的所有数据。
因此需要一个安全的第三方颁发证书(CA),证明双方的身份,防止被中间人攻击。
证书中包括:签发者、证书用途、使用者公钥、使用者私钥、使用者的 HASH 算法、证书到期时间
此时又有新的问题:如果中间人篡改了证书,那么身份证明就无效了,这个时候需要一个新的技术——数字签名。
数字签名就是用 CA 自带的 HASH 算法对证书的内容进行 HASH 得到一个摘要,再用 CA 的密钥加密,最终组成数字签名。当别人把他的证书发过来时,需要用同样的 HASH 算法,再次生成消息摘要,然后用 CA 的公钥对数字签名解密,得到 CA 创建的消息摘要,两者一比较即可知道中间有没有被人篡改。
TLS/SSL的工作原理
TLS / SSL 全程安全传输层协议(Trasnport Layer Security),是介于 TCP 和 HTTP 之间的一层安全协议,不影响原有的 TCP 协议和 HTTP 协议。
SSL 是 TLS 的前身,TLS 弥补了一些安全性和性能方面的缺点,现在广泛使用的是 TLS
采用非对称加密与服务器进行通信,实现身份的验证并协商对称加密使用的密钥。
对称加密算法采用协商密钥对信息以及信息摘要进行加密通信,不同节点之间采用的对称密钥不同,从而保证信息只能通信双方获取。
TLS / SSL 的功能实现主要依赖三类基本算法:
- 散列函数 hash:验证信息完整性
- 对称加密算法:采用协商的密钥对数据加密
- 非对称加密:实现身份认证和密钥协商
- 散列函数 hash
常见的有 MD5,SHA1,SHA256,这些函数的特点是单向不可逆,对输入数据非常敏感,输出的长度固定,任何数据的修改都会改变散列函数的结果,可以用于防止信息篡改并验证数据的完整性。
特点:在信息传输过程中,单靠散列函数不能防止信息篡改,由于传输是明文的,中间人可以篡改信息后重新计算信息的摘要,所以需要对传输的信息和信息摘要进行加密。
- 对称加密
对称加密的方法是,双方使用同一个密钥对数据进行加密和解密。
如果和保证密钥传输的安全性?需要用非对称加密的方法协商对称加密的密钥。
特点:对称加密的优势就是信息传输使用一对一,需要共享相同的密码,密码的安全是保证信息安全的基础,服务器和 N 个客户端通信,需要维持 N 个密码记录且不能修改密码。
- 非对称加密
拥有一个密钥对,公钥是公开的,私钥是保密的。
用公钥加密的数据,只能用私钥解密。
用私钥加密的数据,只能用公钥解密。
我们可以将公钥发布出去,任何想和我们通信的客户,都可以使用我们提供的公钥对数据进行加密,这样我们就可以使用私钥解密。缺点是加密的过程很慢,如果每次通信都是用非对称加密的方式的话,等待时间会太长。
服务端可以实现一对多的通信,因为掌握公钥不同的客户端之间不能相互解密信息。
总结:
TLS / SSL 的工作方式就是客户端使用非对称加密与服务器进行通信,实现身份验证并协商对称加密使用的密钥。
对称加密算法采用协商密钥对信息以及信息摘要进行加密通信,不同节点之间采用的对称密钥不同,从而保证信息只能通信双方获取。
HTTPS 四次握手
(1)首先由客户端向服务器端发送
- 使用的协议的版本号
- 一个随机数
- 可以使用的加密方法
(2)服务器收到后,确认加密方法,向客户端发送
- 选择使用加密方法
- 一个随机数
- 自己的数字证书
(3)客户端收到后,首先检查数字证书是否有效,如果有效
- 生成一个随机数,使用证书中的公钥对随机数进行加密
- 还会生成一个前面所有内容的 hash 以供检验,然后发送给服务端
(4)服务器端收到后
- 使用自己的私钥解密
- 向客户端发送一个前面所有内容的 hash 以供检验
这时候,双方都有三个随机数,按照之前约定的加密方法,使用这三个随机数生成一把密钥,以后双方通信前,就是用这个密钥对数据进行加密后再传输。
详情见 稀土掘金 - HTTPS握手