HTTP协议
2019-12-23
简介
HTTP
(Hyper Text Transfer Protocol-超文本传输协议),是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。是互联网上应用最为广泛的一种网络协议。所有的 WWW 文件都必须遵守这个标准。
超文本传输 协议(HTTP)是用于传输诸如 HTML 的超媒体文档的应用层协议。它被设计用于 Web 浏览器和 Web 服务器之间的通信,但它也可以用于其他目的。HTTP 是一个基于 TCP/IP 通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。也要通过三次握手,四次挥手。
HTTP/0.9
HTTP/0.9
也叫做单行协议。该版本的协议及其简单,只有一个当行命令。包括GET方法和请求路径。响应是一个HTML文档,没有头部和其它元数据。只有HTML,其默认使用的是80端口。
[root@VM_0_5_centos ~]# telnet www.sina.com.cn 80
Trying 111.10.42.194...
Connected to www.sina.com.cn.
Escape character is '^]'.
GET /
<HTML>
<HEAD>
<TITLE>Not Found on Accelerator</TITLE>
</HEAD>
<BODY BGCOLOR="white" FGCOLOR="black">
<H1>Not Found on Accelerator</H1>
<HR>
<FONT FACE="Helvetica,Arial"><B>
Description: Your request on the specified host was not found.
Check the location and try again.
</B></FONT>
<HR>
</BODY>
Connection closed by foreign host.
上面演示了使用HTTP请求的GET /
请求新浪服务器的根文件。
HTTP/0.9
具有如下特点:
- 是客户端与服务器之间的请求响应协议
- ASCII协议,运行于TCP/IP之上
- 被设计用来传输超文本文档HTML
- 服务器与客户端之间的每次连接都会在请求完成之后关闭
HTTP/1.0
随着WEB越来越流行,HTTP/0.9
功能性不足暴露出来。大家需要一种协议不仅能够传输HTML,还能传输其它文档。可以给请求和响应提供元数据。于是1996年HTTP工作组发布 RFC 1945
。不过RFC只是参考性的。HTTP/1.0
并不是一个正式规范。
报文示例:
GET /mypage.html HTTP/1.0
User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
HTTP/1.0 200 OK
Content-Type:text/html
Content-Length:1024
HTTP/1.0
新增特性:
- 请求方法增加了POST和HEAD
- 请求和响应都可以添加首部(请求头,响应头)
- 响应内容前增加了响应状态行
- 响应不局限于HTML,可以用来传输纯文本,图片等其它类型。超文本传输协议名称沿用,但是改成超媒体传输协议似乎更合适。
注意:服务器和客户端的连接在每次请求完成之后关闭,这一点跟HTTP/0.9
一样。
HTTP/1.1
1997年1月,距离HTTP/1.0
发布半年之后,HTTP/1.1
正式发布(RFC 2068),两年半之后,HTTP/1.1
进行了一次大改进(功能增强,性能改进),标志着HTTP/1.1
进入了成熟阶段。
HTTP/1.1
报文示例:
GET /mypage.html HTTP/1.1
User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
HTTP/1.1 200 OK
Content-Type:text/html
Content-Length:1024
Connection:keep-alive
Transfer-Encoding:chunked
100
<!doctype html>
……
100
……
0
GET /favicon.ico HTTP/1.1
User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
Connection:clouse
HTTP/1.1 200 OK
Content-Type:image/x-icon
Content-Length:3638
Etag:W/sdfsd-xxxx
……(图片数据)
Connection closed by foreign host.
HTTP/1.1
主要新增功能:
- 持久连接:底层TCP连接可以在多个请求中重复使用,减少了TCP连接建立关闭的开销,减少TCP慢启动的影响,传输性能明显提升。
- 分块传输编码(Chunk transfer encoding): 服务端生成内容和传输内容可用并行,减少客户端等待时间。 其对内容是动态生成的提供了很好的支持。
- 增强缓存机制:增加 If-None-Match,Etag和Cache-Control等请求响应头部,不依赖于客户端服务端本地时间,更好的支持缓存。
- HTTP管线化
持久连接
HTTP/1.0 每进行一次 HTTP 通信,都需要经历建立 TCP 连接、传输 HTTP 数据和断开 TCP 连接三个阶段。
在当时,由于通信的文件比较小,而且每个页面的引用也不多,所以这种传输形式没什么大问题。但是随着浏览器普及,单个页面中的图片文件越来越多,有时候一个页面可能包含了几百个外部引用的资源文件,如果在下载每个文件的时候,都需要经历建立 TCP 连接、传输数据和断开连接这样的步骤,无疑会增加大量无谓的开销。 为了解决这个问题,HTTP/1.1 中增加了持久连接的方法,它的特点是在一个 TCP 连接上可以传输多个 HTTP 请求,只要浏览器或者服务器没有明确断开连接,那么该 TCP 连接会一直保持。
HTTP 的持久连接可以有效减少 TCP 建立连接和断开连接的次数,这样的好处是减少了服务器额外的负担,并提升整体 HTTP 的请求时间。
持久连接在 HTTP/1.1 中是默认开启的,所以你不需要专门为了持久连接去 HTTP 请求头设置信息,如果你不想要采用持久连接,可以在 HTTP 请求头中加上 Connection: close 。不同浏览器对同一域名所支持的最大连接数不同(网上大多都说默认是6个,但是没找到十分确切的数据。 参考连接 https://yq.aliyun.com/articles/611340 , https://blog.csdn.net/wenshu12321/article/details/69488029)。
分块传输编码
分块传输编码(Chunked transfer encodiing)超文本传输协议(HTTP)中的一种数据传输机制,允许HTTP由网页服务器发送给客户端应用( 通常是网页浏览器)的数据可以分成多个部分。
通常,HTTP应答消息中发送的数据是整个发送的,Content-Length消息头字段表示数据的长度。数据的长度很重要,因为客户端需要知道哪里是应答消息的结束,以及后续应答消息的开始。然而,使用分块传输编码,数据分解成一系列数据块,并以一个或多个块发送,这样服务器可以发送数据而不需要预先知道发送内容的总大小。通常数据块的大小是一致的,但也不总是这种情况。
HTTP 1.1引入分块传输编码提供了以下几点好处:
- HTTP分块传输编码允许服务器为动态生成的内容维持HTTP持久链接。通常,持久链接需要服务器在开始发送消息体前发送Content-Length消息头字段,但是对于动态生成的内容来说,在内容创建完之前是不可知的。
- 分块传输编码允许服务器在最后发送消息头字段。对于那些头字段值在内容被生成之前无法知道的情形非常重要,例如消息的内容要使用散列进行签名,散列的结果通过HTTP消息头字段进行传输。没有分块传输编码时,服务器必须缓冲内容直到完成后计算头字段的值并在发送内容前发送这些头字段的值。
- HTTP服务器有时使用压缩 (gzip或deflate)以缩短传输花费的时间。分块传输编码可以用来分隔压缩对象的多个部分。在这种情况下,块不是分别压缩的,而是整个负载进行压缩,压缩的输出使用本文描述的方案进行分块传输。在压缩的情形中,分块编码有利于一边进行压缩一边发送数据,而不是先完成压缩过程以得知压缩后数据的大小。
如果一个HTTP消息(请求消息或应答消息)的Transfer-Encoding消息头的值为chunked,那么,消息体由数量未定的块组成,并以最后一个大小为0的块为结束。
增强缓存控制
具体可参考 https://www.cnblogs.com/Iwillknow/p/3957183.html
HTTP管线化(不成熟)
持久连接虽然能减少 TCP 的建立和断开次数,但是它需要等待前面的请求返回之后,才能进行下一次请求。如果 TCP 通道中的某个请求因为某些原因没有及时返回,那么就会阻塞后面的所有请求,这就是著名的队头阻塞的问题。
HTTP/1.1 中试图通过管线化的技术来解决队头阻塞的问题。HTTP/1.1 中的管线化是指将多个 HTTP 请求整批提交给服务器的技术,虽然可以整批发送请求,不过服务器依然需要根据请求顺序来回复浏览器的请求,依然会产生队头阻塞(head of line blocking)因此该特性在浏览器默认均不开启,为了实现HTTP请求并发,浏览器大都为每个域名开多个TCP连接。
http/1.0
和http/1.1
中的 Head of line blocking、Multiplexing图释:
HTTP/2.0
HTTP/2.0
主要是为了解决HTTP/1.1
的性能问题(TCP连接不能多路复用),为了达到这个目的,HTTP/2.0
增加了二进制分帧层,保留之前的使用方式不变,功能略有增加。
HTTP/2.0特性
借助二进制分帧层实现多路复用
HTTP/2.0
的性能增强核心,几乎全在二进制分帧层。如下图所示:
在HTTP/2.0
中,TCP连接是以流的方式建立的,如下图所示。
借助二进制分帧层,给每一次交互分配一个流ID,客户端和服务端吧请求和响应分割为一系列的帧,附上流ID,多个流的帧可以交替发送,到另一端再按顺序重新组合。从而实现发送请求和响应时多路复用底层TCP连接,多个请求被分配了多个流ID,不会互相干扰。浏览器只需要给每一个源分配一个连接,大大减少TCP慢启动的影响以及底层连接之间的竞争;同时节省服务端和客户端内存文件描述符资源,简化浏览器对底层连接的管理。
HTTP2.0帧结构
以下是HTTP/2.0
中的常见概念:
- 流:已建立连接(TCP连接)上的双向字节流
- 消息:与请求和响应对应的一些列数据帧
- 帧:
HTTP/2.0
最小通信单位
以下是HTTP/2.0
中的帧结构:
- Length: 24位,一个帧的载荷最大为2的24次方(16MB)
- Type:8位,表示帧类型(DATA,HEADERS,PRIORITY,RST_STREAM,SETTINGS,PUSH_PROMISE,PING,GOAWAY,WINDOW_UPDATE,CONTINUATION)
- Flags: 不同帧类型用于标识不同类型的消息,如END_STREAM表示此流的最后一帧。
- R : 1位,保留位。
- Stream identifer: 流ID,唯一标识流。
HTTP/3.0
HTTP/2.0
作为一个应用层协议,基本已经无可挑剔,然而目前HTTP/2.0
底层依然使用TCP协议作为传输层,由于TCP协议是一个可靠的传输协议,需要把网络分组按序完整的交给应用层,当某一分组丢失时,TCP就会等待发送端重传,已到达分组的暂时放到接受缓存队列中,收到重传后再一起交给应用层。这种情形叫队首阻塞。如果队列中有各个流的分组,则其中一个流的分组丢失会阻塞其他流的数据,导致应用层不能接受。如下图,由于stream2丢失了一个分组,导致stream3和stream4的分组即便都到了接收端,依然不能交给应用层读取。这样HTTP 2.0费尽⼼思设计的二进制分帧层以隔离个流/请求之间的相互影响,由于TCP队首阻塞的存在,还是没有办法真正实现流之间相互不阻塞。
为了彻底解决这个问题,HTTP2.0 over QUIC应运而生。然而QUIC和TCP之间有何区别呢,且看下图,QUIC协议是基于UDP实现的一个可靠的传输层协议,它的拥塞控制比起TCP粒度更细,⼀个QUIC连接里面可以设置很多个流(借鉴HTTP2.0),每个流有自己的拥塞控制和流量控制,这样即使stream2中有一个分组丢失了,只会阻塞在stream2的接收队列,stream3和stream4分组到达后可以立即交给应用层读取,不受stream2影响。2018年年10月,HTTP 2.0 over QUIC已被重新命名为HTTP 3.0