HTTP
-
HTTP是什么?
全称: 超文本传输协议(
HyperText Transfer Protocol
) 。概念:
HTTP
是一种能够获取像HTML
、图片等网络资源的通讯协议(protocol
)。它是在web
上进行数据交换的基础,是一种client-server
协议。HTTP
在因特网的角色:充当一个信使的角色,干的就是一个跑腿的活,在客户端和服务端之间传递信息,但我们又不能缺少它。HTTP
协议是应用层的协议,是与前端开发最息息相关的协议。平时我们遇到的HTTP
请求、HTTP
缓存、Cookies
、跨域等其实都跟HTTP
息息相关。 -
基础特性
- 可拓展协议。
HTTP 1.0
出现的HTTP headers
让协议拓展变得更加的容易。只要服务端和客户端就headers
达成语义一致,新功能就可以被轻松的加入进来 HTTP
是无状态的、有会话的。在同一个连接中,两个执行成功的HTTP
请求之间是没有关系的。这就带来了一个问题,用户没有办法在同一个网站中进行连续的交互,比如在一个电商网站里,用户把某个商品加入到购物车,切换一个页面后再次添加了商品,这两次添加商品的请求之间没有关联,浏览器无法知道用户最终选择了哪些商品。而使用HTTP
的头部扩展,HTTP Cookies
就可以解决这个问题。把Cookies
添加到头部中,创建一个会话让每次请求都能共享相同的上下文信息,达成相同的状态HTTP
通过TCP
或者TLS
——加密的TCP
连接来发送,理论上任何可靠的传输协议都可以使用。连接是传输层控制的,这从根本上来讲不是HTTP
的范畴。 也就是说,HTTP
依赖于面向连接的TCP
进行消息传递,但连接并不是必须的。只需要它是可靠的,或不丢失消息的(至少返回错误)
HTTP/1.0
默认为每一对HTTP
请求/响应都打开一个单独的TCP
连接。当需要连续发起多个请求时,这种模式比多个请求共享同一个TCP
链接更低效。为此,HTTP 1.1
持久连接的概念,底层TCP
连接可以通过connection
头部实现。但HTTP 1.1
在连接上也是不完美的,后面我们会提到。 - 可拓展协议。
-
基于 HTTP 的组件系统
HTTP
的组件系统包括客户端、web
服务器和代理 -
HTTP 报文组成
HTTP
消息由采用ASCII
编码的多行文本构成的。在HTTP/1.1
以及更早的版本中,这些消息通过连接公开的发送。在HTTP2.0
中,消息被分到了多个HTTP
帧中。通过配置文件(用于代理服务器或者服务器),API
(用于浏览器)或者其他接口提供HTTP
消息-
HTTP 请求和响应
HTTP 请求和响应都包括起始行(
start line
)、请求头(HTTP Headers
)、空行(empty line
)以及body
部分 。- 起始行: 请求的起始行:请求方法、请求
Path
和HTTP
版本号 。 - 相应行:响应的起始行:
HTTP
版本号、响应状态码以及状态文本描述 。
下面详细说下请求
Path
,请求路径(Path
)有以下几种:- 一个绝对路径,末尾跟上一个 ’ ? ’ 和查询字符串。这是最常见的形式,称为 原始形式 (
origin form
),被GET
,POST
,HEAD
和OPTIONS
方法所使用 。
POST / HTTP/1.1 GET /background.png HTTP/1.0 HEAD /test.html?query=alibaba HTTP/1.1 OPTIONS /anypage.html HTTP/1.0
- 一个完整的
URL
。主要在使用GET
方法连接到代理的时候使用 。
GET http://developer.mozilla.org/en-US/docs/Web/HTTP/Messages HTTP/1.1
- 由域名和可选端口(以’:'为前缀)组成的
URL
的authority component
,称为authority form
。仅在使用CONNECT
建立HTTP
隧道时才使用。
CONNECT developer.mozilla.org:80 HTTP/1.1
- 星号形式 (
asterisk form
),一个简单的星号(‘*’),配合OPTIONS
方法使用,代表整个服务器。
OPTIONS * HTTP/1.1
-
Headers: 请求头或者响应头。详见下面的首部。不区分大小写的字符串,紧跟着的冒号 (‘:’) 和一个结构取决于
header
的值 。 -
空行。很多人容易忽略
-
Body
请求
Body
部分:有些请求将数据发送到服务器以便更新数据:常见的的情况是POST
请求(包含HTML
表单数据)。请求报文的Body
一般为两类。一类是通过Content-Type
和Content-Length
定义的单文件body
。另外一类是由多Body
组成,通常是和HTML Form
联系在一起的。两者的不同表现在于Content-Type
的值。
Content-Type —— application/x-www-form-urlencoded
对于application/x-www-form-urlencoded
格式的表单内容,有以下特点:
I.其中的数据会被编码成以&分隔的键值对 II.字符以URL编码方式编码。
-
Content-Type —— multipart/form-data
请求头中的
Content-Type
字段会包含boundary
,且boundary
的值有浏览器默认指定。例:Content-Type: multipart/form-data;boundary=----WebkitFormBoundaryRRJKeWfHPGrS4LKe
。 数据会分为多个部分,每两个部分之间通过分隔符来分隔,每部分表述均有HTTP
头部描述子包体,如Content-Type
,在最后的分隔符会加上–表示结束。
```js Content-Disposition: form-data;name="data1"; Content-Type: text/plain data1 ----WebkitFormBoundaryRRJKeWfHPGrS4LKe Content-Disposition: form-data;name="data2"; Content-Type: text/plain data2 ----WebkitFormBoundaryRRJKeWfHPGrS4LKe-- ```
- 起始行: 请求的起始行:请求方法、请求
-
-
方法
安全方法:
HTTP
定义了一组被称为安全方法的方法。GET
方法和HEAD
方法都被认为是安全的,这意味着GET
方法和HEAD
方法都不会产生什么动作 ——HTTP
请求不会再服务端产生什么结果,但这并不意味着什么动作都没发生,其实这更多的是web
开发者决定的。GET
:请求服务器发送某个资源HEAD
:跟GET
方法类似,但服务器在响应中只返回了首部。不会返回实体的主体部分。PUT
:向服务器中写入文档。语义:用请求的主体部分来创建一个由所请求的URL
命名的新文档POST
:用来向服务器中输入数据的。通常我们提交表单数据给服务器。【POST
用于向服务器发送数据,PUT
方法用于向服务器上的资源(例如文件)中存储数据】TRACE
:主要用于诊断。实现沿通向目标资源的路径的消息环回(loop-back
)测试 ,提供了一种实用的debug
机制。OPTIONS
:请求WEB
服务器告知其支持的各种功能。可以询问服务器支持哪些方法。或者针对某些特殊资源支持哪些方法。DELETE
:请求服务器删除请求URL
中指定的的资源
-
GET 和 POST 的区别
首先要了解下副作用和幂等的概念,副作用指的是对服务器端资源做修改。幂等指发送
M
和N
次请求(两者不相同且都大于 1),服务器上资源的状态一致。应用场景上,get是无副作用的,幂等的。post 主要是有副作用的,不幂等的情况。技术上有以下的区分:
- 缓存:
Get
请求能缓存,Post
请求不能 - 安全:
Get
请求没有Post
请求那么安全,因为请求都在URL
中且会被浏览器保存历史记录。POST
放在请求体中,更加安全 - 限制:
URL
有长度限制,会干预Get
请求,这个是浏览器决定的 - 编码:
GET
请求只能进行URL
编码,只能接收ASCII
字符,而POST
没有限制。POST
支持更多的编码类型,而且不对数据类型做限制 - 从
TCP
的角度,GET
请求会把请求报文一次性发出去,而POST
会分为两个TCP
数据包,首先发header
部分,如果服务器响应100(continue)
, 然后发body
部分。(火狐浏览器除外,它的POST
请求只发一个TCP
包)
- 缓存:
-
状态码
-
00~199——信息性状态码
101 Switching Protocols。在HTTP升级为WebSocket的时候,如果服务器同意变更,就会发送状态码 101。
-
200~299——成功状态码
200 OK,表示从客户端发来的请求在服务器端被正确处理
204 No content,表示请求成功,但响应报文不含实体的主体部分
205 Reset Content,表示请求成功,但响应报文不含实体的主体部分,但是与 204 响应不同在于要求请求方重置内容
206 Partial Content,进行范围请求
-
300~399——重定向状态码
301 moved permanently,永久性重定向,表示资源已被分配了新的 URL
302 found,临时性重定向,表示资源临时被分配了新的 URL
303 see other,表示资源存在着另一个 URL,应使用 GET 方法获取资源
304 not modified,表示服务器允许访问资源,但因发生请求未满足条件的情况
307 temporary redirect,临时重定向,和302含义类似,但是期望客户端保持请求方法不变向新的地址发出请求
-
400~499——客户端错误状态码
400 bad request,请求报文存在语法错误
401 unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息
403 forbidden,表示对请求资源的访问被服务器拒绝
404 not found,表示在服务器上没有找到请求的资源
-
500~599——服务器错误状态码
500 internal sever error,表示服务器端在执行请求时发生了错误
501 Not Implemented,表示服务器不支持当前请求所需要的某个功能
503 service unavailable,表明服务器暂时处于超负载或正在停机维护,无法处理请求
-
-
首部 HTTP Headers
-
通用首部(
General headers
)同时适用于请求和响应消息,但与最终消息主体中传输的数据无关的消息头。如Date
-
请求首部(
Request headers
)包含更多有关要获取的资源或客户端本身信息的消息头。如 User-Agent -
响应首部(
Response headers
)包含有关响应的补充信息 -
实体首部(
Entity headers
)含有关实体主体的更多信息,比如主体长(Content-Length
)度或其MIME
类型。如Accept-Ranges
-
-
HTTP 的前世今生
-
HTTP 0.9
- 单行协议,请求由单行指令构成。以唯一可用的方法
GET
开头。后面跟的是目标资源的路径
GET /mypage.html
- 响应:只包括响应文档本身
<HTML> 这是一个非常简单的HTML页面 </HTML>
-
没有响应头,只传输
HTML
文件 -
没有状态码
- 单行协议,请求由单行指令构成。以唯一可用的方法
-
HTTP 1.0
- 协议版本信息会随着每个请求发送
- 响应状态码
- 引入了
HTTP
头的概念,无论是请求还是拓展,允许传输元数据。使协议变得灵活,更加具有拓展性 Content-Type
请求头,具备了传输除纯文本HTML
文件以外其他类型文档的能力 在响应中,Content-Type
标头告诉客户端实际返回的内容的内容类型- 虽然
HTTP1.0
在HTTP 0.9
的基础上改进了很多,但还是存在这不少的缺点。HTTP/1.0
版的主要缺点是,每个TCP
连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。TCP
连接的新建成本很高,因为需要客户端和服务器三次握手,并且开始时发送速率较慢(slow start
)
-
HTTP 1.1
- 连接可以复用。长连接:
connection: keep-alive
。HTTP 1.1
支持长连接(PersistentConnection
),在一个TCP
连接上可以传送多个HTTP
请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1
中默认开启Connection:keep-alive
,一定程度上弥补了HTTP1.0
每次请求都要创建连接的缺点。 - 增加了管道化技术(
HTTP Pipelinling
),允许在第一个应答被完全发送完成之前就发送第二个请求,以降低通信延迟。复用同一个TCP
连接期间,即便是通过管道同时发送了多个请求,服务端也是按请求的顺序依次给出响应的;而客户端在未收到之前所发出所有请求的响应之前,将会阻塞后面的请求(排队等待),这称为"队头堵塞"(Head-of-line blocking
)。 - 支持响应分块,分块编码传输:
Transfer-Encoding: chunked``Content-length
声明本次响应的数据长度。keep-alive
连接可以先后传送多个响应,因此用Content-length
来区分数据包是属于哪一个响应。使用Content-Length
字段的前提条件是,服务器发送响应之前,必须知道响应的数据长度。对于一些很耗时的动态操作来说,这意味着,服务器要等到所有操作完成,才能发送数据,显然这样的效率不高。更好的处理方法是,产生一块数据,就发送一块,采用"流模式"(Stream
)取代"缓存模式"(Buffer
)。因此,HTTP 1.1
规定可以不使用Content-Length
字段,而使用"分块传输编码"(Chunked Transfer Encoding
)。只要请求或响应的头信息有Transfer-Encoding: chunked
字段,就表明body
将可能由数量未定的多个数据块组成。每个数据块之前会有一行包含一个 16 进制数值,表示这个块的长度;最后一个大小为 0 的块,就表示本次响应的数据发送完了。 - 引入额外的缓存控制机制。在
HTTP1.0
中主要使用header
里的If-Modified-Since
,Expires
等来做为缓存判断的标准,HTTP1.1
则引入了更多的缓存控制策略例如Entity tag
,If-None-Match
,Cache-Control
等更多可供选择的缓存头来控制缓存策略。 Host
头。不同的域名配置同一个IP
地址的服务器。Host
是HTTP 1.1
协议中新增的一个请求头,主要用来实现虚拟主机技术。 虚拟主机(virtual hosting
)即共享主机(shared web hosting
),可以利用虚拟技术把一台完整的服务器分成若干个主机,因此可以在单一主机上运行多个网站或服务
- 连接可以复用。长连接:
-
HTTP 2.0
- 二进制协议。http2.0是一个二进制协议,基本单位是帧,引入了二进制数据帧和流的概念:客户端发送请求时,请求会被分解为多个帧,同一个请求的帧的流标识符相同,每个请求可以理解为一个包含多个帧的流。在二进制分帧层上,http2.0会将所有传输信息分割为帧,并对他们采用二进制格式的编码将其封装。新增的二进制分帧层同时也能保证http的各种动词,方法,首部都不受影响,兼容上一代http标准。
- 多路复用。新的分帧层机制,http2.0不再依赖多个TCP连接去实现多流并行:每个数据流(请求/相应)都被拆分成很多互不依赖的帧,因为有标识符字段,因此帧可以无序发送(多个请求分解成帧通过一个TCP连接交错发送),最后当帧到达服务器后,根据流标识符来重新组合得到完整的请求。http2.0的TCP连接都是持久化的,而且客户端与服务器之间也只需要一个连接(每个域名一个链接)即可,此连接可以承载数十/数百个流的复用。
- 压缩了
headers
。HTTP1.x
的header
带有大量信息,而且每次都要重复发送,就造成了性能的损耗。为了减少此开销和提升性能,HTTP2.0
使用HPACK
压缩格式压缩请求和响应标头元数据,这种格式采用两种简单但是强大的技术:这种格式支持通过静态霍夫曼代码对传输的标头字段进行编码,从而减小了各个传输的大小。这种格式要求客户端和服务器同时维护和更新一个包含之前见过的标头字段的索引列表(换句话说,它可以建立一个共享的压缩上下文),此列表随后会用作参考,对之前传输的值进行有效编码。 - 服务端推送。其允许服务器在客户端缓存中填充数据,通过一个叫服务器推送的机制来提前请求。服务器向客户端推送资源无需客户端明确地请求,服务端可以提前给客户端推送必要的资源,这样可以减少请求延迟时间,例如服务端可以主动把
JS
和CSS
文件推送给客户端,而不是等到HTML
解析到资源时发送请求,这样可以减少延迟时间
-
-
HTTPS
-
HTTPS
也是通过HTTP
协议进行传输信息,但是采用了TLS
协议进行了加密。 -
对称加密和非对称加密
- 对称加密就是两边拥有相同的秘钥,两边都知道如何将密文加密解密。但是因为传输数据都是走的网络,如果将秘钥通过网络的方式传递的话,一旦秘钥被截获就没有加密的意义的
- 公钥大家都知道,可以用公钥加密数据。但解密数据必须使用私钥,私钥掌握在颁发公钥的一方。首先服务端将公钥发布出去,那么客户端是知道公钥的。然后客户端创建一个秘钥,并使用公钥加密,发送给服务端。服务端接收到密文以后通过私钥解密出正确的秘钥
-
TLS 握手过程( 非对称加密 )
Client Hello
: 客户端发送一个随机值(Random1
)以及需要的协议和加密方式Server Hello
以及Certificate
: 服务端收到客户端的随机值,自己也产生一个随机值(Random2
),并根据客户端需求的协议和加密方式来使用对应的方式,并且发送自己的证书(如果需要验证客户端证书需要说明)Certificate Verify
: 客户端收到服务端的证书并验证是否有效,验证通过会再生成一个随机值(Random3
),通过服务端证书的公钥去加密这个随机值并发送给服务端,如果服务端需要验证客户端证书的话会附带证书Server 生成 secret
: 服务端收到加密过的随机值并使用私钥解密获得第三个随机值(Random3
),这时候两端都拥有了三个随机值,可以通过这三个随机值按照之前约定的加密方式生成密钥,接下来的通信就可以通过该密钥来加密解密
-
-
HTTP 缓存
-
强缓存: 主要是由
Cache-control
和Expires
两个Header
决定的Expires
的值和头里面的Date
属性的值来判断是否缓存还有效。Expires
是Web
服务器响应消息头字段,在响应http
请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。Expires
的一个缺点就是,返回的到期时间是服务器端的时间,这是一个绝对的时间,这样存在一个问题,如果客户端的时间与服务器的时间相差很大(比如时钟不同步,或者跨时区),那么误差就很大。Cache-Control
指明当前资源的有效期,控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据。但是其设置的是一个相对时间。
Cache-control优先级比 Expires优先级高!
-
协商缓存
If-Modified-Since——Last-Modified
Last-Modified
表示本地文件最后修改日期,浏览器会在request header
加上If-Modified-Since
(上次返回的Last-Modified
的值),询问服务器在该日期后资源是否有更新,有更新的话就会将新的资源发送回来但是如果在本地打开缓存文件,就会造成
Last-Modified
被修改,所以在HTTP / 1.1
出现了ETag
If-none-match——ETags
Etag
就像一个指纹,资源变化都会导致ETag
变化,跟最后修改时间没有关系,ETag
可以保证每一个资源是唯一的。If-None-Match
的header
会将上次返回的Etag
发送给服务器,询问该资源的Etag
是否有更新,有变动就会发送新的资源回来If-none-match、ETags 优先级高于 If-Modified-Since、Last-Modified!
-