HTTP协议
在HTTP建立之初,主要就是为了将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器。
HTTP是超文本传输协议。它是应用层协议的一种,请求/响应报文的组成结构
报文格式
请求报文的格式
1 | GET / |
- 三个部分
1 | 请求行 |
响应报文的格式
1 | 200 OK |
- 三个部分
响应行
请求头,都是以 key-value形式组成
实体主体
HTTP的特点
无连接
无连接, 每次请求有一个建立连接和释放连接的过程
可以通过HTTP的持久连接方案来进行HTTP无连接的一个补偿
非持久连接,在 Client 和 Server 的交互中,打开一个 TCP 连接,进行网络数据的传输,然后关闭这条 TCP 连接. 之后发送第二个请求的时候可能需要重新打开一个 TCP 的连接 。 也就是说每次请求接口都需要重新建立一个 TCP 连接,经历 三次握手 四次挥手.
持久连接 , 打开一条 TCP 通道,之后可能在一定时间内, 多个 HTTP 请求可能会在同一条链路上进行请求和响应的传递.
持久连接涉及到 HTTP 的哪些头部字段呢?
1 | Connection : keep-alive 客户端期许采用持久连接 |
状态码
1 | 1xx 代表临时响应,需要请求者继续执行操作的状态代码。 |
GET和POST请求的区别
- GET 请求参数以 ? 分割拼接到 URL 后面 ,POST请求参数在 Body里面
- GET 参数长度限制 2048 个字符 , POST一般没有该限制
- GET 请求不安全 , POST请求比较安全
从语义的角度来回答
- GET 获取资源 ,安全的 , 幂等的 , 可缓存的
- POST 处理资源 ,非安全的 ,非幂等的 , 非可缓存的
- 安全性 : 不应该引起 Server 端的任何状态变化
- 幂等行 : 同一个请求方法执行多次和执行一次的效果完全相同
- 请求是否可以被缓存
HTTP连接管理
连接模式
HTTP有两种连接模式,持续连接、非持续连接
非持续连接 指的是服务器必须为每一个请求的对象建立和维护一个全新的连接
持续连接下,TCP 连接默认不关闭,可以被多个请求复用,采用持续链接的好处是可以避免每次建立TCP连接三次握手时所花费的时间。
1 | HTTP1.0 以前默认使用非持续链接,但是可以在请求时,加上Connection:keep-alive来要求服务器不要关闭TCP连接 |
目前对于同一个域,大多数浏览器支持同时建立6个持久连接
无连接?有连接?
无连接:限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
无连接的含义可以结合HTTP无状态的含义在应用层面上去理解:每一个请求都拥有自己的请求体,期望接收到唯一的对应的响应体,而每一次的请求都相互独立,与上一次或下一次的请求毫无关系,哪怕是在同一条连接中(后面说的长连接)。
1 | TCP的面向连接是基于网络底层的数据传输。 |
从短连接到长连接
HTTP/0.9:最早发布的1991年0.9版,该时期的HTTP协议十分简单,只支持Get请求,采用短连接的方式,也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。
HTTP/1.0:1996年发布,默认使用短连接,提出长连接(也叫持久连接)的概念,但当时仅提供初步的支持。
HTTP/1.1:1999年发布,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:Connection:keep-alive
1 | HTTP/1.1 版本的默认连接都是持久连接。为此,客户端会在持久连接上连续发送请求。当服 |
持久连接的特点是,只要任意一端 没有明确提出断开连接,则保持 TCP 连接状态。
1 | 在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的 |
HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。
TCP短连接长连接都由客户端发起,而TCP长连接的保活功能主要为服务器应用提供。如果客户端已经消失而连接未断开,则会使得服务器上保留一个半开放的连接,而服务器又在等待来自客户端的数据,此时服务器将永远等待客户端的数据。保活功能就是试图在服务端器端检测到这种半开放的连接。也因为短连接、长连接的实现在HTTP之外,与HTTP无关,从HTTP自身来看,HTTP依然是无连接的。
Keep Alive
在HTTP/1.1之前的协议中,每一次通信就会连接和断开一次TCP链接。
在每一次的请求和响应都是一次完整的TCP连接的建立和断开,TCP的握手和挥手的开销对于频繁的通信来说是不可接受的。所以为了解决这个问题,提出了持久连接。也就是keep alive.
这样做的优点:
- 减少TCP握手和挥手的开销
- 减轻了服务器的负载
你以为做就完美了吗?其实不然,每一次通信都需要HTTP响应,才能发送下一个包,这样效率岂不是很慢。所以就引入了管线化技术。
从HTTP/1.1到HTTP/2
HTTP/1.1:pipelining 管线化
持久连接使得多数请求以管线化(pipelining)方式发送成为可能。从前发送请求后需等待并收到响应,才能发送下一个请求。管线化技术出现后,不用等待响应亦可直接发送下一个请求
HTTP/1.1时期,持久连接(长连接)的弊端被提出 —— HOLB(Head of Line Blocking)即持久连接下一个连接中的请求仍然是串行的,如果某个请求出现网络阻塞等问题,会导致同一条连接上的后续请求被阻塞
因此,HTTP/1.1中提出了pipelining概念,即客户端可以在一个请求发送完成后不等待响应便直接发起第二个请求,服务端在返回响应时会按请求到达的顺序依次返回,这样就极大地降低了延迟。然而pipelining并没有解决HOLB的问题,因为响应依然是串行返回的,pipelining也因此没有被广泛接受。
所以现代浏览器默认是不开启 HTTP Pipelining 的。
HTTP/2:multiplexing ( HTTP2 都是在 HTTPS 上实现的)
multiplexing即多路复用,连接共享,在SPDY中提出,同时也在HTTP/2中实现。multiplexing技术能够让多个请求和响应的传输完全混杂在一起进行,通过streamId来互相区别。这彻底解决了HOLB问题,同时还允许给每个请求设置优先级,服务端会先响应优先级高的请求。
pipelining和multiplexing的对比,如图:
HTTP的长连接和WebSocket的长连接
HTTP的长连接:HTTP/1.1通过使用Connection:keep-alive进行长连接。在一次 TCP 连接中可以完成多个 HTTP 请求,但是对每个请求仍然要单独发 header,Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。这种长连接是一种“伪链接”,而且只能由客户端发送请求,服务端响应。
WebSocket的长连接,是一个全双工的连接,可由服务端主动发起信息。长连接第一次TCP链路建立之后,后续数据可以双方都进行发送,不需要发送请求头。
1 | HTTP/1.1中双方并没有建立正真的连接会话,服务端可以在任何一次请求完成后关闭。 |
常见问题
怎样判断一个请求是否结束?
在同一条TCP上产生了多次 HTTP 请求,怎样判断前一个请求的结束
Content-length : 1024 , 发送一个请求的时候,Server 端会携带响应数据的大小,通过 Content-length 来标识,客户端可以根据所接受数据的字节数是否到达 Content-length 的值,到达了就说明全部接受完毕,既 HTTP 请求结束
还有一种情况, 当使用 POST 端进行请求的时候 , 往往 Server 端需要多次响应来返回给客户端数据, 我们可以通过 HTTP 响应报文当中的头部字段叫 chunked 来判断请求是否结束,当有多个块通过 HTTP 的 TCP连接传输给客户端的时候,每一个报文都会带有chunked 这个字段, 最后一个块会带有一个空 chunked,这样就可以判断前一个网络请求是否结束了.