# HTTP
HTTP
是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范。
超文本传输协议,是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准
(TCP)
,用于从WWW
服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
# 报文
HTTP
报文分为两种:HTTP
请求报文(请求行-HTTP
头(通用信息头,请求头,实体头)-请求报文主体(只有POST
才有报文主体)。响应报文则相对应的为状态行,响应报文主体。
通用信息头指的是请求和响应报文都支持的头域,分别为
Cache-Control
、Connection
、Date
、Pragma
、Transfer-Encoding
、Upgrade
、Via
;实体头则是实体信息的实体头域,分别为Allow
、Content-Base
、Content-Encoding
、Content-Language
、Content-Length
、Content-Location
、Content-MD5
、Content-Range
、Content-Type
、Etag
、Expires
、Last-Modified
、extension-header
。
常用头部字段解释:
TIP
Content-Length
服务器返回数据时会有该字段,表明本次的回应数据长度
Content-Type
⽤于服务器回应时,告诉客户端,本次数据是什么格式
Content-Type: text/html;charset=utf-8
Content-Type: application/json;charset=utf-8
2
客户端请求的时候,可以使用
Accept
字段声明自己可以接受哪些数据格式
Accept: */*
# HTTP历史
HTTP/0.9
只有一个请求行,没有
HTTP
请求头和请求体。同样,服务器也没有响应头信息,只是返回了数据。因为都是HTML
格式的文件,决定了返回的文件内容通过ASCII
字符流进行传输。
HTTP/1.0
引入请求头/响应头,引入状态码,为了减轻服务器压力提供了
Cache
机制。服务器需要统计客户端的基础信息(Windows
和macOS
),加入了用户代理字段。有两个问题:
TCP
连接无法复用,每次请求都需要重新建立TCP
通道,这就需要重复进行三次握手和四次挥手,也就是说每个TCP
连接只能发送一个请求。- 队头阻塞,即使多个请求并行发出,也只能一个一个进行响应。
HTTP/1.1
TIP
- 改进持久连接(长连接,默认开启
Connection:keep-alive
)
一个TCP
连接上可以传输多个HTTP
请求,只要浏览器或者服务器没有断开连接,该TCP
会一直保持。持久连接是默认开启的,如果想要关闭,在请求头中加上Connection:close
即可关闭。目前浏览器中对于同一个域名,默认允许同时建立6
个TCP
持久连接。
- 增加对虚拟主机的支持
HTTP/1.0
中每个域名都只绑定唯一的IP
地址,因此一个服务器只能支持一个域名。但是随着虚拟主机技术的发展,一台物理主机上绑定多个虚拟主机的需求大大提升,每个虚拟主机都有自己单独的域名,这些单独的域名都公用同一个IP
地址。因此,请求头中也增加了Host
字段,表示当前的域名地址,服务器可根据不同的Host
值做不同的处理。
- 增加对动态生产内容的支持
HTTP/1.0
需要在响应头中设置完整的数据大小Content-Length:900
,这样,浏览器就可以根据设置的数据大小来接收数据。由于服务器端技术发展,页面都是动态生成的,传输数据之前并不知道最终数据大小,导致浏览器不知道何时会接受完所有的文件数据。HTTP/1.1
通过引入Chunk transfer
机制来解决问题,服务器将数据分割成若干个任意大小的数据块,每个数据块发送时会附上上一个数据块的长度,最后使用一个长度为0
的块作为发送数据完成的标志。
- 客户端
Cookie
,安全机制 - 未完全解决
http 1.0
的队头阻塞问题:请求之间是串行的。如果发送了A
请求,那么A
请求的响应返回之前,你的B
请求不管多么着急发出去,都要取决了A
请求是否结束了。http1.1
则利用了不成熟的管线化来解决这个问题。管线化是指:允许多个HTTP
请求批量地提交给服务器。不过这样做仍然没有从根本上解决队头阻塞的问题--虽然发送动作可以并行,不过服务器依然需要根据请求顺序来回复浏览器的请求,也就是说响应仍然是串行的。A
如果一年没有被响应,B
也休想被响应。 所以很多浏览器默认禁用管线化特性。 - 增加了与缓存相关的请求头。进行了带宽优化,并能够使用
range
头等来支持断点续传功能。新增错误类型,并增强了错误和响应码的语义特性。新增了Host
头处理,如果请求消息中没有Host
头,则会报错。
HTTP 1.1
缺点:
- 没有真正解决队头阻塞问题
- 明文传输,安全性问题
header
中携带的内容过多,增加传输成本- 默认开启
keep-alive
可能会给服务器端造成性能压力,比如一次性的请求,在文件被请求之后还保持了很长时间不必要的连接。- 由于
TCP
慢启动机制,导致每个TCP
连接在一开始的时候传输速率都不高,在处理多个请求后,才会慢慢达到 “合适” 的速率。对于请求数据量很小的HTTP
请求来说,这种情况就是种灾难。HTTP/1.1
无法为重要的资源指定优先级,每个HTTP
请求都是一视同仁。受限的优先级设置
HTTP/2.0
(基于HTTPS
)
二进制协议将通信传输信息分解为帧,这些帧交织在客户端和服务端之间的双向逻辑流中,使所有通信都可以在单个
TCP
连接上执行,而且该连接在整个对话期间一直处于打开状态。
使用多路复用机制解决
TCP
慢启动(一旦一个TCP
连接建立之后,就进入了发送数据状态,刚开始TCP
协议会采用一个非常慢 的速度去发送数据,然后慢慢加快发送数据的速度,直到发送数据的速度达到一个理想状态,我们把这个过程称为慢启动慢启动是TCP
为了减少网络拥塞的一种策略,我们是没有办法改变的);开启多条TCP
连接会竞争固定带宽;队头阻塞的问题。(一个域名只使用一个TCP
长连接和消除队头阻塞问题。通过引入二进制分帧层,实现了HTTP
的多路复用技术。)。这是因为一个请求对应一个流并分配了一个id
,这样一个连接上可以有多个流,所以流的帧都可以相互混杂在一起,接收方可以根据流的id
将帧分配到各自不同的请求中。同一个TCP
连接中可以发送多个请求,对端可以通过帧中的标识知道该帧属于哪一个请求。
服务器可以提前将数据推送到浏览器,浏览器有权选择是否接受。浏览器发送
RST_STREAM
帧可以选择拒收。在浏览器刚请求HTML
的时候,就提前把可能会⽤到的JS、CSS
⽂件等静态资源主动发给客户端,减少延时的等待,也就是服务器推送(Server Push
,也叫Cache Push
)
头部的压缩大大的提升了传输效率。
HTTP/2
开发了“HPACK
”算法,在客户端和服务器建立“字典”,用索引号表示重复的字符串,还采用哈夫曼编码来压缩整数和字符串。客户端和服务器分别维护一份相同的静态字典,这个字典用来存储常见的头部名称,以及常见的头部名称和值的组合。同时还会维护一份相同的动态字典,这个字典可以随时更新。如此一来,第一次相互通信之后后面的请求只需要发送与前面请求之间头部不同的地方,其他头部信息都可以从字典里获取。相对于HTTP1.x
中每次都要携带整个头部跑来跑去,大大节省了网络开销。
流优化先:消息帧通过流进行发送。我们提到了为每个流分配了一个
id
,那么也同样可以为它们分配优先级。这样一来,服务器端可以根据优先级确定它的处理顺序。
可以设置让某些重要的数据优先被服务器处理并返回。针对服务器端希望发送的每个资源,服务器端都会发送一个
PUSH_PROMISE
帧,但客户端可以通过RST_STREAM
帧作为响应来拒绝推送。当一个客户端主动请求资源K时,如果服务器端知道它很可能也需要资源M,那么服务器端就会主动将资源M推送给客户端。当客户端真的请求M时,便可以从缓存中读取
流控制:客户端哦通知服务器停止发送数据,以免耗尽自身的缓存。
TIP
HTTP/2
主要的问题在于,多个HTTP
请求在复⽤⼀个TCP
连接,下层的TCP
协议是不知道有多少个HTTP
请求的。所以⼀旦发⽣了丢包现象,就会触发TCP
的重传机制,这样在⼀个TCP
连接中的所有的HTTP
请求都必须等待这个丢了的包被重传回来。这都是基于TCP
传输层的问题,所以HTTP/3
把HTTP
下层的TCP
协议改成了UDP
HTTP/3.0
TIP
TCP
以及TCP+TLS
建立连接的延时
HTTP/2
都是使用TCP
协议来传输的,而如果使用HTTPS
的话,还需要使用TLS
协议进行安全传输,而使用TLS
也需要一个握手过程,这样就需要有两个握手延迟过程:
- 在建立
TCP
连接的时候,需要和服务器进行三次握手来确认连接成功,也就是说需要在消耗完1.5
个RTT
之后才能进行数据传输。 - 进行
TLS
连接,TLS
有两个版本——TLS1.2
和TLS1.3
,每个版本建立连接所花的时间不同,大致是需要1~2
个RTT
。
总之,在传输数据之前,我们需要花掉 3~4
个 RTT
。
TCP
的队头阻塞并没有彻底解决 上文我们提到在HTTP/2
中,多个请求是跑在一个TCP
管道中的。但当出现了丢包时,HTTP/2
的表现反倒不如HTTP/1
了。因为TCP
为了保证可靠传输,有个特别的“丢包重传”机制,丢失的包必须要等待重新传输确认,HTTP/2
出现丢包时,整个TCP
都要开始等待重传,那么就会阻塞该TCP
连接中的所有请求。而对于HTTP/1.1
来说,可以开启多个TCP
连接,出现这种情况反到只会影响其中一个连接,剩余的TCP
连接还可以正常传输数据。
UDP
发⽣是不管顺序,也不管丢包的,所以不会出现HTTP/1.1
的队头阻塞 和HTTP/2
的⼀个丢包全部重传问题。⼤家都知道UDP
是不可靠传输的,但基于UDP
的QUIC
协议 可以实现类似TCP
的可靠性传输。
QUIC
有⾃⼰的⼀套机制可以保证传输的可靠性的。当某个流发⽣丢包时,只会阻塞这个流,其他流不会受到影响。TLS3
升级成了最新的1.3
版本,头部压缩算法也升级成了QPack
。HTTPS
要建⽴⼀个连接,要花费6
次交互,先是建⽴三次握⼿,然后是TLS/1.3
的三次握⼿。QUIC
直接把以往的TCP
和TLS/1.3
的6
次交互合并成了3
次,减少了交互次数
QUIC
是⼀个在UDP
之上的伪TCP + TLS + HTTP/2
的多路复⽤的协议。QUIC
是新协议,对于很多⽹络设备,根本不知道什么是QUIC
,只会当做UDP
,这样会出现新的问题。
# HTTP
状态码
1xx
:请求已经收到,但是处理过程还没结束,需要客户端再抛出一个请求才能完成整个过程(即需要进一步处理才能完成),HTTP1.0
不支持100 Continue
:上传大文件前使用101 Switch Protocols
:协议升级使用102 Processing
:服务器已经收到并正在处理请求,但无响应可用
2xx
:成功处理请求200 OK
:成功返回响应201 Created
:有新资源在服务器端被成功创建202 Accepted
:服务器接受并开始处理请求,但请求未处理完成206 Partial Content
:使用range
协议时返回部分响应内容时的响应码
重定向是服务器发起的跳转,要求客户端使用新的
URI
重新发送请求。在响应头字段Location
中指示了要跳转的URI
。使用Refresh
字段,还可以实现延时重定向。
3xx
:重定向301
/302
是常用的重定向状态码。分别代表永久性重定向和临时性重定向。303
:类似于302
,重定向后的请求方法改为GET
方法307
:类似于302
,含义比302
更明确,重定向后请求的方法和实体不允许变动308
:类似于301
,代表永久重定向,重定向后请求的方法和实体不允许变动300
:是一个特殊的重定向状态码,会返回一个有多个链接选项的页面,由用户自行选择304
:是一个特殊的重定向状态码,服务端验证过期缓存有效后,要求客户端使用该缓存
4xx
:客户端出现错误400 Bad Request
:服务器认为客户端出现了错误,但不明确,一般是HTTP
请求格式错误
产生原因;前端提交数据的字段名称和字段类型与后台的实体没有保持一致;前端提交到后台的数据应该是
json
字符串类型,但是前端没有将对象JSON.stringfy
转换为字符串401 Unauthorized
:用户认证信息确实或者不正确。发送的请求需要通过HTTP
认证。403 Forbidden
:服务器理解请求的含义,但没有权限执行407 Proxy Authentication Required
:对需要经由代理的请求,认证信息未通过代理服务器的验证404 Not Found
:服务器没有找到对应的资源408 Request Timeout
:服务器接收请求超时405 Method Not Allowed
:请求方法不被服务端允许。
5xx
:服务器端出现错误500 Internal Server Error
:服务器内部错误,且不属于以下错误类型502 Bad Gateway
:代理服务器无法获取到合法响应503 Service Unavailable
:服务器资源尚未准备好处理当前请求。服务器当前很忙,暂时无法响应505 HTTP Version Not Supported
:请求使用的HTTP
协议版本不支持
# HTTP几种方法
GET
:发送一个请求来获取服务器上的某一些资源POST
:向URL指定的资源提交数据或附加新的数据 GET和POST的区别PUT
:跟POST
方法一样,可以向服务器提交数据,但是它们之间也所有不同,PUT
指定了资源在服务器的位置,而POST
没有哦。HEAD
:指请求页面的首部。DELETE
:删除服务器上的某资源OPTIONS
:它用于获取当前URL
所支持的方法,如果请求成功,在Allow
的头包含类似GET,POST
等的信息。 复杂请求的理解TRACE
:用于激发一个远程的,应用层的请求消息回路。CONNECT
:把请求连接转换到TCP/TP
通道。