HTTP协议学习笔记
一、简介
HTTP 协议用于客户端和服务器端之间的通信。请求访问文本或图像等资源的一端称为客户端,而提供资源响应的一 端称为服务器端。HTTP 协议规定,请求从客户端发出,最后服务器端响应该请求并返回。
- HTTP 是不保存状态的协议 【为了实现期望的保持状态功能,于 是引入了 Cookie 技术】
- HTTP 协议使用 URI 定位互联网上的资源 【统一资源标识符,和URL(一资源定位符)的区别】URI表示请求服务器的路径,定义这么一个资源;而URL同时说明要如何访问这个资源
- 无连接 【HTTP基于请求-响应模式通信】
二、HTTP方法
GET | 获取资源 |
POST | 传输实体主体 |
PUT | 传输文件 |
HEAD | 获得报文首部 |
DELETE | 删除文件 |
OPTIONS | 询问支持的方法 |
TRACE | 追踪路径 |
CONNECT | 要求用隧道协议连接代理 |
GET和POST都是用于请求数据的,它们之间有什么不同之处呢?
HTTP协议是基于TCP/IP协议的应用层协议,在传输层,TCP协议将HTTP协议打包进行传输,也就是说,GET和POST的实际传输过程是没有区别的;
我们都知道,GET方法请求数据时,请求的信息是要写进URL的,而POST是写在body中,因此这也造就了它们之间的不同;
举个例子,如果参数是 name=xiaoming.c, age=22
则GET方法:
GET /index.php?name=xiaoming.c&age=22 HTTP/1.1
Host: localhost
POST方法:
POST /index.php HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
name=xiaoming.c&age=22
所以:GET方法数据在地址栏可见;URL有长度限制;参数类型有限;参数保留在浏览器历史中…
三、HTTP报文
请求报文
客户端发送一个HTTP请求到服务器的请求消息包括以下格式:
请求行(request line)、请求头部(header)、空行和请求数据
请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本。举个例子:
GET方法
GET /562f25980001b1b106000338.jpg HTTP/1.1
Host img.mukewang.com
User-Agent Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36
Accept image/webp,image/*,*/*;q=0.8
Referer http://www.imooc.com/
Accept-Encoding gzip, deflate, sdch
Accept-Language zh-CN,zh;q=0.8
POST方法
POST / HTTP1.1
Host:www.wrox.com
User-Agent:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
Content-Type:application/x-www-form-urlencoded
Content-Length:40
Connection: Keep-Alive
name=Professional%20Ajax&publisher=Wiley
响应报文
一般情况下,服务器接收并处理客户端发过来的请求后会返回一个HTTP的响应消息。
HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。
状态行 :协议版本+状态码 |
---|
响应首部字段 |
空行 |
请求正文 |
举个例子:
HTTP/1.1 200 OK
Date: Fri, 22 May 2009 06:07:21 GMT
Content-Type: text/html; charset=UTF-8
<html>
<head></head>
<body>
<!--body goes here-->
</body>
</html>
状态码
状态码描述返回的请求结果,以 3 位数字和原因短语组成
四、报文首部
报文结构
请求报文首部
响应报文首部
首部字段给浏览器和服务器提供报文主体大小、所使用的语言、认证信息等内容,其结构为 首部字段名: 字段值
通用首部字段
首部字段 | 说明 |
---|---|
Cache-Control | 缓存行为控制 |
Connection | 控制不再转发给代理的首部字段;管理持久连接 |
Date | 创建 HTTP 报文的日期和时间 |
Pragma | 历史遗留字段 |
Trailer | 事先说明在报文主体后记录了哪些首部字段 |
Transfer-Encoding | 报文主体采用的编码方式 |
Upgrade | 升级为指定的其他协议 |
Via | 追踪客户端与服务器之间的请求和响应报文的传输路径 |
Warning | 告知用户一些与缓存相关的问题的警告 |
Cache-Control
控制缓存的行为
缓存请求指令
缓存响应指令
no-cache不是不缓存,而是不缓存过期资源, no store才是不缓存
Connection
- 控制不再转发给代理的首部字段 Connection: 不再转发的首部字段名
- 管理持久连接 Connection: Keep-Alive
Date
创建 HTTP 报文的日期和时间
Pragma
历史遗留字段
Trailer
事先说明在报文主体后记录了哪些首部字段,可应用在 HTTP/1.1 版本分块传输编码
Transfer-Encoding
规定了传输报文主体时采用的编码方式,HTTP/1.1 的传输编码方式仅对分块传输编码有效
Upgrade
-
用于检测 HTTP 协议及其他协议是否可使用更高的版本进行通信
-
参数值可以用来指定一个完全不同的通信协议
-
需要额外指定Connection:Upgrade
-
服务器可用 101 Switching Protocols 状态码作为响应返回
Via
追踪报文的传输路径,报文经过代理或网关时,会先在首部字段 Via 中附加该服务器的信息,然后再进行转发
Warning
告知用户一些与缓存相关的问题的警告,格式 Warning: [警告码][警告的主机:端口号]“[警告内容]”([日期时间])
请求首部字段
Accept
通知服务器,用户代理能够处理的媒体类型及媒体类型的相对优先级
例如:Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset
通知服务器用户代理支持的字符集及字符集的相对优先顺序,可一次性指定多种字符集
例如:Accept-Charset: iso-8859-5, unicode-1-1;q=0.8
Accept-Encoding
告知服务器用户代理支持的内容编码及内容编码的优先级顺序,可一次性指定多种内容编码
Accept-Language
告知服务器用户代理能够处理的自然语言集(指中文或英文等),以及自然语言集的相对优先级,可一次指定多种自然语言集
Authorization
告知服务器,用户代理的认证信息(证书值)
Expect
告知服务器,期望出现的某种特定行为,无法理解客户端的期望作出回应而发生错误时,会返回状态码 417 Expectation Failed
From
告知服务器使用用户代理的用户的电子邮件地址
Host
告知服务器,请求的资源所处的互联网主机名和端口号,未设定主机名,发送空值
条件请求
形如 If-xxx 这种样式的请求首部字段,都可称为条件请求,只有判断指定条件为真时,才会执行请求
If-Match
告知服务器匹配资源所用的实体标记(ETag)值,不匹配(可以使用星号(*)指定),返回状态码 412 Precondition Failed 的响应
If-Modified-Since
确认代理或客户端拥有的本地资源的有效性
指定的日期时间后,资源发生了更新,服务器会接受请求
未更新,返回状态码 304 Not Modified 的响应
If-None-Match
与 ETag 值不一致时,可处理该请求(与If-Match相反)
在 GET 或 HEAD 方法中使用首部字段 If-None-Match 可获取最新的资源
If-Range
告知服务器若指定的 If-Range 字段值(ETag 值或者时间)和请求资源的 ETag 值或时间相一致时,则作为范围请求处理。反之,则返回全体资源。
If-Unmodified-Since
与If-Modified-Since 的作用相反
Max-Forwards
每次转发数值减 1。当数值变 0 时返回响应
Proxy-Authorization
告知服务器认证所需要的信息
Range
告知服务器资源的指定范围
返回状态码为 206 Partial Content 的响应
无法处理该范围请求时,则会返回状态码 200 OK 的响应及全部资源
Referer
告知服务器请求的原始资源的 URI,出于安全性的考虑时,也可以不发送
TE
告知服务器客户端能够处理响应的传输编码方式及相对优先级
User-Agent
将创建请求的浏览器和用户代理名称等信息传达给服务器
响应首部字段
Accept-Ranges
告知客户端服务器是否能处理范围请求,以指定获取服务器端某个部分的资源,可处理范围请求时指定其为 bytes,不能处理范围请求时,Accept-Ranges: none
Age
告知客户端,源服务器在多久前创建了响应
ETag
告知客户端实体标识,ETag 值由服务器来分配
强 ETag 值:不论实体发生多么细微的变化都会改变其值 ETag: "usagi-1234"
弱 ETag 值:只有资源发生了根本改变,产生差异时才会改变 ETag 值 ETag: W/"usagi-1234"
Location
以将响应接收方引导至某个与请求 URI 位置不同的资源
配合 3xx :Redirection 的响应
Proxy-Authenticate
把由代理服务器所要求的认证信息发送给客户端
Retry-After
-
告知客户端应该在多久之后再次发送请求
-
配合状态码 503 Service Unavailable 响应,或 3xx Redirect
-
可以指定为具体的日期时间(Wed, 04 Jul 2012 06:34:24GMT 等格式),也可以是创建响应后的秒数
Server
告知客户端当前服务器上安装的 HTTP 服务器应用程序的信息 Server: Apache/2.2.6 (Unix) PHP/5.2.5
Vary
可对缓存进行控制
WWW-Authenticate
用于 HTTP 访问认证,状态码 401 Unauthorized 响应中,肯定带有首部字段 WWW-Authenticat
实体首部字段
Content-MD5 检查报文主体在传输过程中是否保持完整,以及确认传输到达
为 Cookie 服务的首部字段
Set-Cookie
Cookie
当客户端想获得 HTTP 状态管理支持时,就会在请求中包含从服务器接收到的 Cookie
五、HTTP各个版本的特点
HTTP1.0
-
无状态、无连接
无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。随着网页变得越来越复杂,一个网页中有许多图像和文本,而TCP连接的建立和释放都需要消耗资源和时间,无连接的方式就显得有点低效率了。
无状态是指协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。即客户端给服务器发送 HTTP 请求之后,服务器根据请求给客户端发送数据但不会记录任何信息。现实中,事务的处理往往是承前启后的,我们需要知道前一刻的状态才知道这一刻可以做什么,于是,就有了cookie/session机制。
Cookie可以保持登录信息到用户下次与服务器的会话,换句话说,下次访问同一网站时,用户会发现不必输入用户名和密码就已经登录了。注意:cookie值是由服务器生成发送给客户端,保存在客户端的
-
无法复用连接 ——网络的利用率低
HTTP无连接
- 队头阻塞
必须等到接收到上一条请求的响应时才能发送下一条请求
HTTP1.1
- 长连接
HTTP的长连接说的是TCP的连接。在HTTP1.0中,每发送一次请求就会建立一条TCP连接,比较低效,因此,HTTP1.1添加了首部字段Connection:keep-alive
,并设置Keep-Alive: timeout=60
来控制连接的保持时间。实现长连接需要客户端和服务端都支持长连接。
- 管道化
管线化是把多个HTTP请求放到一个TCP连接中一一发送,而在发送过程中不需要等待服务器对前一个请求的响应,只不过,客户端还是要按照发送请求的顺序来接收响应。实际上是将客户端的FIFO队列移到了服务端
- 缓存处理
我们访问一个资源的时候,如果本地有“已缓存的副本”,就可以直接从本地提取这个资源。
缓存处理涉及的首部字段如下:
首部字段 | 值 | 说明 |
---|---|---|
Cache-Control | no-cache, no-store, must-revalidate, max-age, public, private | 控制浏览器是否可以缓存资源、强制缓存校验、缓存时间 |
If-Match/If-None-Match | ETag值 | 告知服务器匹配资源所用的实体标记(ETag)值 |
If-Modified-Since/If-Unmodified-Since | 指定日期 | 指定的日期时间后,资源发生了更新,服务器会接受请求 |
ETag | hash码、时间戳等可以标识文件是否更新 | 强校验,根据文件内容生成精确 |
Last-Modified | 请求的资源最近更新时间 | 弱校验, 根据文件修改时间,可能内容未变,不精确 |
Expires | 资源缓存过期时间 | 与响应头中的 Date 对比 |
Cache-control指令已介绍过,这里就不再赘述。
HTTP缓存的流程如下:
- 断点传输
HTTP1.1 协议(RFC2616)开始支持获取文件的部分内容,这为并行下载以及断点续传提供了技术支持。
它通过在 Header 里两个参数实现的,客户端发请求时对应的是 Range ,服务器端响应时对应的是 Content-Range。
Rang格式:Range:(unit=first byte pos)-[last byte pos]
Range: bytes=0-499 表示第 0-499 字节范围的内容
Range: bytes=-500 表示最后 500 字节的内容
Range: bytes=500- 表示从第 500 字节开始到文件结束部分的内容
Range: bytes=0-0,-1 表示第一个和最后一个字节
Range: bytes=500-600,601-999 同时指定几个范围
Content-Range格式:Content-Range: bytes (unit first byte pos) - [last byte pos]/[entity legth]
Content-Range: bytes 0-499/22400
需要考虑的是:如果在传输过程中,资源发生变化要如何识别和处理?
实体首部字段中有两个字段:Last-Modified和Etag,Last-Modified表示请求的资源最近更新时间,ETag为资源的标识,可以类比为对象的hashCode。有了这两个字段我们就可以在发送请求时添加If-Range首部字段验证资源是否过期/发生变化。如果未发生变化,服务器会返回状态码为 206 Partial 的响应,以及相应的消息主体;如果资源已更新,那么就会返回状态码为 200 OK 的响应,同时返回整个****资源。
HTTP2.0
- 二进制分帧
HTTP 2.0最大的特点: 不会改动HTTP 的语义,HTTP 方法、状态码、URI 及首部字段,等等这些核心概念上一如往常,却能致力于突破上一代标准的性能限制,改进传输性能,实现低延迟和高吞吐量。HTTP2性能增强的核心就是二进制分帧。
在应用层(HTTP2.0)和传输层(TCP or UDP)之间增加一个二进制分帧层,将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码 ,其中HTTP1.x的首部信息会被封装到Headers帧,而request body则封装到Data帧里面。HTTP/2 通信都在一个连接上完成,这个连接可以承载任意数量的双向数据流。每个数据流以消息的形式发送,而消息由一或多个帧组成,这些帧可以乱序发送,帧中包含流标识符,可以重新组装。
- 多路复用
多路复用对同一域名下所有请求都是基于流,所以不存在同域并行的阻塞。每一个TCP连接中承载了多个双向流通的流,每一个流都有一个独一无二的标识和优先级,而流就是由二进制帧组成的。二进制帧的头部信息会标识自己属于哪一个流,所以这些帧是可以交错传输,然后在接收端通过帧头的信息组装成完整的数据。这样就解决了线头阻塞的问题,同时也提高了网络速度的利用率。
- 头部压缩
HTTP报文中的冗余 header 字段不必要地消耗了带宽,从而显著增加了延迟。通过压缩首部字段,可以有效的减少报文中首部字段的长度。
HTTP2采用的压缩算法为HPACK算法,该算法维护一个静态字典和动态字典,静态字典中包括了61个常用的首部字段和值。
一个示例如下:
- 服务器推送
HTTP/2允许服务器在请求之前先推送响应信息到客户端(之前客户端有过请求),如果实现了HTTP缓存,推送的响应信息可以在客户端被缓存(可通过no-cache进行配置)。