目录
HTTP 是什么?
HTTP 是 Web 客户端与服务器之间进行传输文字、图片、音频、视频等超文本数据的约定和规范。
百度百科:超文本传输协议(Hyper Text Transfer Protocol)是一个简单的请求-响应协议,它通常运行在 TCP 之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以 ASCII 形式给出;而消息内容则具有一个类似 MIME 的格式。这个简单模型是早期 Web 成功的有功之臣,因为它使开发和部署非常地直截了当。
HTTP 常见的状态码有哪些?
状态码 | 类别 | 含义 |
1XX | Informational(信息性状态码) | 接收的请求正在处理 |
2XX | Success(成功状态码) | 请求正常被服务器处理完毕 |
3XX | Redirection(重定向状态码) | 需要进行附加操作以完成请求 |
4XX | Client Error(客户端错误状态码) | 服务器无法处理请求 |
5XX | Server Error(服务器错误状态码) | 服务器处理请求出错 |
1XX 信息
- 100 Continue:目前为止都很正常,客户端可以继续发送请求或者忽略这个响应。
2XX 成功
- 200 OK:请求被成功发送与响应,响应报文中有响应行、响应头和响应体。
- 204 Not Content:请求被成功发生与响应,但与 200 OK 不同,它没有响应体。一般在只需要从客户端往服务器发送信息,而不需要返回数据时使用。
- 206 Partial Content:表示客户端进行了范围请求,响应报文包含由 Content-Range 指定范围的实体内容。如果网络出现中断,服务器只发送了一部分数据,范围请求可以使得客户端只请求服务器未发送的那部分数据,从而避免服务器重新发送所有数据。
3XX 重定向
- 301 Move Permanently:永久性重定向,表示请求的资源已不复存在,需要使用新的 URL 进行访问。
- 302 Found:临时性重定向,表示请求的资源暂时还存在,但仍需使用新的 URL 进行访问。
301 和 302 都会在响应头中使用字段 Location 来表示要跳转的 URL ,浏览器会自动重定向至该 URL 。
- 304 Not Modified:不具有跳转的含义,表示资源未修改,重定向至已存在的缓冲文件,也称缓存重定向,用于缓存控制。
4XX 客户端错误
- 400 Bad Request:请求报文中存在语法错误。
- 403 Forbidden:客户端请求被服务端拒绝,客户端访问了禁止访问的资源所造成。
- 404 Not Found:客户端请求的资源在服务端找不到。
5XX 服务端错误
- 500 Internal Server Error:服务器执行请求时发生错误。
- 502 Bad Gateway:通常是服务器作为网关或代理时出现的错误码,表示服务器自身正常,但经其访问的后端服务器出现异常。
- 503 Service Unavailable:服务器当前很忙,处于超负载或正在进行停机维护,现在无法处理请求。
HTTP 常见首部字段有哪些?
HTTP 有 4 种类型的首部字段:通用首部字段、请求首部字段、响应首部字段和实体首部字段。
首部字段是 请求报文 / 响应报文 中的 请求头 / 响应头 中的字段。
请求头和响应头也称为首部行(参考《计算机网络:自顶向下方法》P69)。
通用首部字段
- Connection:通常用于指定 TCP 连接是持续性的长连接还是一次性的。
- HTTP/1.1 开始默认是长连接,需要由客户端或者服务器端主动提出断开,使用 Connection : close。
- HTTP/1.1 之前默认是短链接,需要使用 Connection : keep-alive 进行长连接。
- Cache-Control:控制缓存的行为。
请求首部字段
- Host:客户端发送请求时,用来指定服务器的域名。
- Accept:表示客户端想接收、可处理的实体媒体类型。
- Accept-Encoding:客户端可接收的、优先的字符编码。客户端浏览器通过发送 Accept-Encoding 首部,其中包含有它所支持的压缩算法(常用的内容编码有:gzip、deflate),以及各自的优先级。服务器则从中选择一种,使用该算法对响应的消息主体进行压缩,并且发送 Content-Encoding 首部来告知浏览器它选择了哪一种算法。
响应首部字段
- Location:令客户端重定向至指定 URL
实体首部字段
- Content-Length:请求体或响应体的字节大小。
- Content-Type:请求体或响应体的媒体类型。如: text/html; charset=UTF-8 表示实体类型为网页,且字符编码是 UTF-8 。
- Content-Encoding:实体主体适用的编码方式。
GET 和 POST 请求方法的区别?
GET 和 POST 都是请求报文的请求行中的请求方法字段,用来表明使用何种请求方法。
作用
- GET:用于从服务器获取资源。
- POST:用于传输实体数据(表单)给服务器。实体数据放在请求体中。
参数
- GET:请求参数携带在 URL 之后。URL 只支持 ASCII 编码,若想携带中文的参数,要先进行编码。
- POST:请求参数存储在请求体中。POST 请求体中的参数支持标准字符集。
不能因为 POST 参数存储在实体主体中就认为它的安全性更高,因为照样可以通过一些抓包工具(Fiddler)进行查看。
安全
安全的 HTTP 方法是只读的,它不会改变服务器的状态。
- GET 方法是安全的,因为它只用来获取服务器上的资源,不会改变服务器状态。
- POST 方法是不安全的,因为 POST 的目的是传送实体主体内容,这个内容可能是用户上传的表单数据,上传成功之后,服务器可能把这个数据存储到数据库中,因此状态也就发生了改变。
安全的方法除了 GET 之外还有:HEAD、OPTIONS。
不安全的方法除了 POST 之外还有 PUT、DELETE(但它们可以是幂等的)。
幂等性
幂等的 HTTP 请求方法,表明同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的。
- GET 方法是幂等的,所有安全的方法都是幂等的,包括 HEAD、OPTIONS。
- POST 方法是不幂等的,因为假如调用多次增加数据到数据库的请求方法,则服务器的状态就会发生改变。POST 方法同时也是不安全的方法,但不安全的方法不一定就不幂等,PUT 和 DELETE 这两个不安全的请求方法也可以是幂等的。
DELETE 是幂等的,因为数据只有一个,删除一次之后就算继续连续调用也无法再删除了,此时响应回来的状态码可能由 200 变为 404 。
对 HTTP 的了解?
HTTP 特性
HTTP 协议是无状态协议。
- 好处:由于服务器不用花费额外的资源去记忆状态,所以能够减轻服务器的负担,把 CPU 和内存用来对外提供更多的服务,也就是说,无状态使得 HTTP 协议更加简单,不必记录状态,使得它能够处理大量的事务。
- 坏处:由于服务器没有记忆能力,在完成形如 登录-->购买商品-->付款 等一系列关联动作时每次都需要重新验证一次身份,会变得非常麻烦。
HTTP/1.1 引入了 Cookie 将用户信息保存在客户端浏览器中:客户端浏览器第一次发送请求时,服务端会响应回一个 Cookie ,浏览器在之后的请求中只要携带该 Cookie 便可被服务器所认出。
除了可以将用户信息通过 Cookie 存储在用户浏览器中,也可以利用 Session 存储在服务器端,存储在服务器端的信息更加安全。比如 Session 可以存储在服务器上的文件、数据库或者内存中。也可以将 Session 存储在 Redis 这种内存型数据库中,效率会更高。
HTTP 优点
- 简单。
- 灵活、易扩展。
- 应用广泛、跨平台。
HTTP 缺点
不安全,存在安全问题:
- 使用明文进行通信,通信内容可能被窃听;
- 无法验证通信方的身份,身份可能被伪装;
- 无法验证报文的完整性,报文可能被篡改。
对 HTTPS 的了解?
由于 HTTP 协议存在安全性问题,所以有了 HTTPS :通过在 HTTP 协议与 TCP 协议之间加入了 SSL/TLS 协议,通过隧道的方式让 HTTP 与 SSL/TLS 先通信,再由 SSL/TLS 与 TCP 通信。
应该注意到 HTTPS 并不是一个新的协议,只是通过引入 SSL/TLS 协议,使 HTTP 具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)的功能,这也就是 HTTPS 。
加密:HTTPS 使用混合加密的方式,既保证了安全性又提高了效率
1. 对称密钥加密:加密和解密使用同一密钥。
- 优点:运算速度快。
- 缺点:不安全,无法安全地将密钥传输给彼此。
2. 非对称密钥加密:加密和解密使用不同的密钥,分为公钥和私钥。
接收方的公钥所有人都可以获取,但私钥只有它自己拥有;任一发送方获得接收方的公钥之后,就可以使用公钥对通信内容进行加密然后传输,接收方收到通信内容后就可以使用自己的私钥对其进行解密。
非对称密钥除了用来加密,还可以用来进行数字签名。因为私钥无法被他人获取,因此发送方使用其私钥进行数字签名,接收方使用发送方的公钥对签名进行解密,即可判断这个签名是否属于发送方。
- 优点:加密和解密使用不同的密钥,传输更安全。
- 缺点:运算速度慢。
3. TTPS 采用混合加密的形式
- 使用非对称密钥加密方式,传输对称密钥加密方式所需要的私钥 (Secret Key),从而保证安全性。
- 获取到私钥 (Secret Key) 后,再使用对称密钥加密方式进行通信,从而保证效率。
发送方获取到接收方的公钥后就可对自己的私钥进行加密,从而保证了发送方的私钥可以安全地传输给接收方,接收方再用自己的私钥进行解密,即可安全地获得发送方的私钥。此后发送方和接收方都可用发送方的私钥进行对称密钥加密的方式来通信。
采用混合加密的形式,既保证了安全性又提高了效率。
(下图中的 Session Key 就是私钥 (Secret Key))
认证:使用 CA 经私钥数字签名后携带服务器公钥的证书来认证服务器身份
CA:数字证书认证机构 CA(Certificate Authority)是客户端与服务器双方都可信赖的第三方机构。
数字签名:发送方使用自己的私钥对通信内容进行签名,接收方使用发送方的公钥进行解密,若解密成功,则证明了通信内容就是该发送方发过来的。由此可见,私钥不仅可以用来解密,也可以用来加密,数字签名就是使用私钥进行加密,另一方可以使用其公钥解密,解密成功即可认证其身份。
证书:服务器将自己的公钥发送给 CA,CA 会生成一个将其公钥和身份绑定起来的证书,接着 CA 会使用自己的私钥对证书进行数字签名,随后 CA 就将经由自己的私钥进行数字签名后的证书发送给服务器。
认证过程:服务器发送证书给客户端,客户端获取到证书后使用浏览器或操作系统自带的 CA 公钥对证书的数字签名进行真实性确认即解密,确认无误后便可信任该服务器的身份,可以使用携带在证书中的服务器的公钥。
完整性保护:SSL/TLS 提供报文摘要算法生成指纹来进行完整性保护
SSL/TLS 提供的摘要算法能够为通信内容明文生成第一无二的指纹,明文与指纹一同加密后发送给接收方,接收方解密后对解密后的明文再进行一次摘要算法计算出另一个指纹,如果此时计算出来的指纹与接收到的指纹相同,则说明接收到的报文是完整的从发送方发送过来的,没有经过篡改。
注意:HTTP 也提供了 MD5 报文摘要功能,但不是安全的。例如报文内容被篡改之后,同时重新计算 MD5 的值,通信接收方是无法意识到发生篡改的。
HTTPS 的缺点?
- 速度比 HTTP 慢,因为有一系列加密解密的过程,但同时也更安全,有得有失。
- 需要支付证书授权的高额费用。
HTTPS 如何建立连接?其间交互了什么?
HTTPS 与 HTTP 不同的地方在于多了 SSL/TLS 协议握手阶段的四次通信来产生会话密钥进而进行后序的加密通信。
1. ClinetHello
TCP 三次握手建立连接之后,客户端向服务器发起加密通信 HTTPS 请求:ClientHello。
这一步中,客户端向服务器发送的消息有:
- 客户端支持的 SSL/TLS 协议版本,如 TLS 1.2 版本。
- 客户端生成的随机数 ( Client Random ) ,后面用于生成会话密钥。
- 客户端支持的密码套件列表,如 RSA 加密算法。
2. ServerHello
服务器收到客户端请求后,向客户端发出响应:ServerHello。
这一步中,服务器响应给客户端的内容有:
- 确认 SSL/TLS 协议版本,如果浏览器不支持,则关闭加密通信。
- 服务器生成的随机数 ( Server Random ) ,后面用于生成会话密钥
- 确认的密码套件列表,如 RSA 加密算法。
- 服务器的经由 CA 数字签名后的证书。
3. 客户端回应
客户端先通过浏览器或操作系统中自带的 CA 公钥对服务器发来的证书进行真实性验证。
如果验证通过,客户端就会从证书中取出服务器的公钥,用公钥加密报文,回应服务器以下内容:
- 又一个随机数 ( pre-master key ) ,和之前不同,该随机数会被取出的公钥加密。
- 一个通知:加密通信算法改变的通知,表示随后的信息都将用会话密钥加密通信。
- 又一个通知:客户端 SSL/TLS 握手阶段结束的通知。这一项同时把之前所以内容的数据做个摘要,用来供服务器校验。
客户端回应给服务器端后,服务器端和客户端就都有了3个随机数,接着就用它们协商好的加密算法,各自生成本次通信的会话密钥。
4. 服务器的最后回应
服务器收到客户端的第三个随机数之后,通过协商的加密算法,计算出本次通信的会话密钥,然后向客户端发送最后的信息:
- 一个通知:加密通信算法改变的通知,和客户端一样,表示随后的消息都将用会话密钥来进行加密的通信。
- 一个通知:服务器握手结束通知,表示服务器握手阶段结束。这一项同时把之前的所以数据内容做个摘要,供客户端校验。
至此,整个 SSL/TLS 的握手阶段全部结束,接下来,客户端与服务器进去加密通信,就完全是使用普通的 HTTP 协议,只不过用会话密钥加密内容。
HTTP 与 HTTPS 的区别?
- 安全:HTTP 协议比较简单,效率高但却不安全;HTTPS 则相对复杂,效率慢一点但却很安全:通过在 HTTP 和 TCP 之间加了一层 SSL/TLS 协议使 HTTP 变得更安全,让其拥有了加密、认证和完整性保护这三大功能。
- 资源:HTTP 建立连接的时候相对简单,在 TCP 三次握手之后便可进行报文传输;而 HTTPS 则需要在 TCP 三次握手之后增加 SSL/TLS 握手阶段的四次通信才能进行加密的报文传输。HTTPS 相对复杂需要消耗更多的 CPU 和内存。
- 端口:HTTP 的端口号是 80,而 HTTPS 是 443。
- 开销:HTTPS 还需要向数字证书认证机构 CA 认证其身份并获取数字证书,需要支付一定的费用。
HTTP/1.1 比 HTTP/1.0 多了哪些优化?
- 长连接:早期的 HTTP/1.0 默认是短连接的,每发送一次请求就要进行一次 TCP 连接,也就是三次握手的过程,极大的增加了服务器的负载;从 HTTP/1.1 开始则默认使用了长连接的方式,只要客户端或服务器没有主动地断开连接,那就可以复用 TCP 连接,改善了性能的同时也缓解了资源的开销。
- 流水线:HTTP/1.1 支持管道(pipeline)传输,类似于流水线,只要第一个请求发送出去了,就可以继续发送第二个请求,不用等待第一个请求的响应回来了之后才发送,这极大的减少了整体的响应时间。但要注意,服务器响应请求是按顺序来的,会先响应第一个请求后再响应第二个请求,也就是说,如果第一个请求久久得不到响应,那就会阻塞到客户端后面所有的请求,这称为队头阻塞。
- 支持同时打开多个 TCP 连接:HTTP/1.1 要想实现并发通信,就得开启多个 TCP 连接;但要注意,如果同时开启的 TCP 连接数量过多,就会造成极大的 TCP 握手消耗,造成高延迟。
- 虚拟主机:HTTP/1.1 使用虚拟主机技术,使得一台服务器拥有多个域名,并且在逻辑上可以看成多个服务器。
HTTP/2.0 对 HTTP/1.1 做了哪些优化?
首先应该清楚:HTTP/2.0 是基于 HTTPS 的,所以安全性也有了保证。
HTTP/1.1 存在以下缺点:
- HTTP 首部冗长且重复:请求头或响应头里的一些首部字段经常被重复发送,且发送的首部信息都过于冗长,比如携带了 cookie 的首部一般都很冗长。
- 并发连接有限 + 队头阻塞高延迟 + 无法设置优先级:HTTP 要想实现并发通信,只能开启多条 TCP 连接,但比如说像谷歌浏览器的最大并发 TCP 连接数是 6 个,往往达不到并发的要求,而且每一个连接都要经过 TCP 和 TLS 握手的耗时,以及 TCP 慢启动过程给流量带来的影响,极大地增加服务器的负载;并且 HTTP/1.1 是基于请求-响应模型的,一条 TCP 连接里的多条请求虽说可以进行流水线式的持续发送,但响应请求时却只能等待前一个请求响应完成后才能响应后一个请求,如果前一个请求迟迟无法响应,就会造成队头阻塞从而形成了高延迟;同时多个请求也无法设置优先级。
- 不支持服务器主动推送消息:客户端无论需要啥资源都得主动发送请求去服务器取,而无法通过服务器主动地推送附加的资源,这无疑浪费了大量的带宽。
HTTP/2.0 据此做了如下优化:
首部压缩
HTTP/2.0 使用了 HPACK 算法:由字典(静态字典+动态字典)+ Huffman 编码构成。
- 字典:HPACK 算法要求客户端和服务器同时维护和更新一个使用过的首部字段表,称为字典,所有使用过的首部字段都会存入该表并生成对应的索引号,此后如果再使用到该表中的首部字段,则直接发送对应的索引号即可,避免了首部字段被重复传输。
- Huffman 编码:HPACK 算法还利用了 Huffman 编码来压缩首部信息,避免首部信息过于冗长。
二进制分帧层 + 数据流 实现低延迟的并发传输
HTTP/2.0 优秀的地方就在于它使用了二进制格式进行数据传输,不再像 HTTP/1.1 中的纯文本式的报文;还将报文分成了 HEADERS 帧和 DATA 帧,也都是二进制格式的。
服务器收到报文后就可以直接解析二进制格式的帧,极大地提高了数据解析和传输效率。
HTTP/2.0 总共定义了 10 种类型的帧,一般分为数据帧和控制帧两类 。
其次,HTTP/2.0 另一个强大的地方是:在一条 TCP 连接中使用多条 Stream 数据流来代替 HTTP/1.1 中需要使用多条 TCP 连接才能实现并发的问题。
也就是说在客户端和服务器进行通信时,仅仅只需要一条 TCP 连接即可,该连接里面可以同时存在多个 Stream 数据流来实现客户端与服务器的通信从而实现并发。
并且多个 Stream 数据流互不干扰,数据流既可以从客户端发出来也可以从服务端发出来,并且每个数据流都有一个 Stream ID,要求从客户端发出来的 Stream 数据流的 ID 是奇数的,而从服务端发出来的 Stream 数据流的 ID 是偶数的;注意,Stream ID 会携带在每一个帧的头部;并且同一个连接中的 Stream ID 是不能复用的,只能顺序递增,所以当 Stream ID 耗尽时,需要发一个控制帧 GOAWAY ,用来关闭 TCP 连接。
HTTP/2.0 的 Stream 数据流解决了 TCP 并发连接数量受限制的问题也减少了多条 TCP 连接时的握手消耗问题;并且 Stream 数据流的设计也解决了 HTTP/1.1 的队头阻塞问题降低了延迟,多个请求可以分别包含在 Stream 数据流中,谁到了服务器谁就可以被处理然后响应回客户端,不必互相进行等待;还可以为每个 Stream 流设置优先级,同时到达的 Stream 流可以根据优先级进行响应处理。
每条 Stream 数据流中包含消息(Message),消息里面又是一系列的帧(Frame)
- 消息(Message)是就等价于是请求消息和响应消息,里面包含了由帧构成的报文。
- 帧(Frame)是最小的通信单位,来自不同数据流的帧可以交错发送,然后再根据每个帧头的 Stream ID 流标识符来重新组装。
服务端主动推送资源
HTTP/2.0 在服务端请求一个资源时,会把相关的资源一起发送给客户端,客户端就不需要再次发起请求了。例如客户端请求 page.html 页面,服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端。
客户端发起的请求,必须使用奇数号 Stream ID,服务器主动的推送,使用的是偶数号 Stream ID。
服务器在响应回客户端一开始仅需要的资源时,如果服务端有附加的资源需要推送,就会连带着响应一个 PUSH_PROMISE 帧,帧中 HTTP 首部字段 Promised Stream ID 字段告知客户端,接下来会在哪个偶数号 Stream ID 中发送附带的资源。
应该注意:此时响应给客户端的消息会在两个 Stream 中,这两个 Stream 完全可以做到并发到达客户端:一个是客户端原先的奇数 Stream ,服务器正常返回一个客户端需要的资源;另一个是服务器附带的偶数 Stream,里面包含着服务器附带的资源需要推送给客户端。
至此 HTTP/2.0 基于 HTTPS 的模型图可以抽象的表示为