报文流
报文的组成部分
它们由三个部分组成:
- 对报文进行描述的起始行(start line)
- 包含属性的首部(header)块
- 以及可选的、包含数据的**主体(body)**部分。
起始行和首部就是行分隔的ASCII文本。每行都以一个由两个字符组成的行终止符序列作为结束,其中包含一个回车符(ASCII码13)和一个换行符(ASCII码10)。 这个行终止序列可以写作CRLF。
主体是一个可选的数据块。与起始行和首部不同的是,主体中可以包含文本或者二进制数据,也可以为空。
上图中,首部给出了一些与主体有关的信息:
- content-type行说明了主体是什么----纯文本文档。
- content-length行说明了主体有多大----19个字节
报文的语法
所有的HTTP报文都可以分为两类:
- 请求报文(request message):请求报文会向Web服务器请求一个动作
- 响应报文(response message):响应报文会将请求的结果返回给客户端。
这是请求报文的格式:
这是响应报文的格式(注意,只有起始行的语法有所不同):
-
方法
<method>
:- 客户端希望服务器对资源执行的动作
- 是一个单独的词,比如GET/HEAD/POST
-
请求URL
<request-URL>
:- 命名了所请求的资源,或者URL路径组件的完整URL
-
版本
<version>
:- 报文所使用的HTTP版本,其格式如下:
HTTP/<major>.<minor>
- 其中major和minor都是整数
-
状态码
<status>
:- 这三个数据描述了请求过程中所发生的情况
- 每个状态码的第一位数字都用于描述状态的一般类别(“成功”、"出错"等)
-
原因短语
<reason-phrase>
:- 数字状态码的可读版本,包含行终止序列之前的所有文档
- 原因短语只对人类有意义,也就是说,HTTP/1.0 200 NOT OK和HTTP/1.0 200 OK中原因短语的含义不同,但是都会被当成成功指示处理
- 但是,请使用HTTP规范定义的状态码的原因短语示例
-
首部(header):
- 可以有零个或者多个首部,每个首部都包含一个名字,后面跟着一个
:
,然后是一个可选的空格,接着是一个值,最后是一个CRLF
- 可以有零个或者多个首部,每个首部都包含一个名字,后面跟着一个
-
主体(entity-body):
- 包含一个由任意数据组成的数据块
- 并不是所有的报文都包含实体。
起始行
所有的HTTP报文都以一个起始行作为开始。
- 请求报文的起始行说明了要做些什么。
- 响应报文的请示行说明了发生了什么。
请示行
请求报文请求服务器对资源进行一些操作。请求报文的起始行,即请求行,包含了一个方法和一个请求URL,以及HTTP的版本:
- 方法描述了服务器应该执行的操作
- 请求URL描述了要对哪个资源指向这个方法
- HTTP版本用来告知服务器,客户端使用的是哪种HTTP
所有这些字符都由空格符分隔。
响应行
响应报文承载了状态信息和操作产生的所有结果数据,将其返回给客户端。响应报文的起始行,即响应行,包含了响应报文使用的HTTP版本、数字状态码、以及描述操作状态的文本形式的原因短语。
所有这些字符都由空格符分隔。
方法
请求行以方法作为开始,方法用来告知服务器要做些什么。比如GET /aaa HTTP/1.1
中,方法就是GET
HTTP规范中定义了一组常用的请求方法:
另外,除了这些方法外,其他服务器可能还会实现一些自己的请求方法,这些附加方法是对HTTP规范的扩展,因此被称为扩展方法。
状态码
方法用来告诉服务器要做什么事情,状态码用来告知客户端,发生了什么事情。状态码位于响应行中,比如HTTP/1.0 200 OK中,状态码就是200
可以通过三位数字代码对不同的状态码进行分类,如下:
原因短语
原因短语是响应行中最后一个组件。它为状态码提供了文本形式的解释。比如,HTTP/1.0 200 OK中,原因短语就是OK
原因短语和状态码是成对出现的,原因短语是状态码的可读版本,应用程序开发者将其传递给用户,用以说明在请求期间发生了什么情况。
版本号
版本号会以HTTP/x.y的形式出现在请求和响应报文的起始行中。为HTTP应用程序提供了一种将自己所遵循的协议版本告知对方的方式。
使用版本号的目的是为使用HTTP的应用程序提供一种线索,以便相互了解对方的能力和报文格式。
首部
HTTP首部字段向请求和相应报文中添加了一些附加信息。本质上来说,它们是一些名/值对列表。比如,下面的首部行会向Content-Length首部字段赋值19:
- Content-length:19
首部分类
HTTP规范定义了几种首部字段。应用程序也可以随意发明自己所用的首部。HTTP首部可以分为一下几类:
- 通用首部:既可以出现在请求报文中,也可以出现在响应报文中
- 请求首部:提供更多有关请求的信息
- 响应首部:提供更多有关响应的信息
- 实体首部:描述主体的长度和内容,或者资源自身。
- 扩展首部:规范中没有定义的新首部
每个HTTP首部都有一种简单的语法:名字后面跟着:
,然后跟上可选的空格,在跟上字段值,最后是一个CRLF。
首部延续行
将长的首部行分为多行可以提高可读性,多出现的每行前面至少要有一个空格或者制表符(Tab):
在这个响应报文中包含了一行Server首部,其值被分为多个延续行,该首部的完整值为“Test Server Version 1.0”。
实体的主体部分
HTTP报文的第三部分是可选的实体主体部分。实体的主体是HTTP报文的负荷。就是HTTP要传输的内容。
HTTP报文可以承载很多类型的数字数据:图片、视频、HTML文档、软件应用程序等
首部
首部和方法配合工作,共同决定了客户端和服务器能做什么事情。
通用首部
客户端和服务器都可以用的首部
Connection
HTTP协议使用TCP来管理连接方式,主要有两种连接方式,持久性连接和非持久性连接。
持久性连接
- 持久性连接指的是一次会话完成后,TCP连接并未关闭,第二次再次发送请求后,就不再需要建立TCP连接,而是可以直接进行请求和响应。
- 从HTTP 1.1开始,默认使用持久性连接。
- 它的一般表示形式如下:
keep-alive也是一个通用标头,一般Connection都会和keep-alive -起使用,keep-alive 有两个参数,一个是timeout ;另一个是max,它们的主要表现形式如下
- timeout:指的是空闲连接必须打开的最短时间,也就是这次请求的连接时间不能少于5秒
- max:值的是在连接关闭前服务器所能接收的最大请求数
非持久性连接
- 非持久性连接表示一次会话请求/响应后关闭连接的方式。
- HTTP 1.1之前使用的连接都是非持久连接
- 它的一般表示形式如下:
Date
说明报文是什么时间创建的。
Date是一个通用标头,它可以出现在请求标头和响应标头中,它的基本表示如下
表示的是格林威治标准时间,这个时间要比北京时间慢八个小时
MIME-Version
给出了发送端使用的MIME版本
Trailer
- 仅用户当报文采用了分块传输编码时
- 说明在报文主体后记录了哪些首部字段
- 一般用法如下:
以上用例中,指定首部字段Trailer的值为Expires,在报文主体之后(分块长度0之后)出现了首部字段Expires。
Transfer-Encoding
告知接收端为了保证报文的可靠传输,对报文采用了什么编码方式。
Update
给出了发送端可能想要“升级”使用的新版本或者协议
上图用例中, 首部字段Upgrade 指定的值为TLS/1.0 。请注意此处两个字段 首部字段的对应关系,Connection 的值被指定为Upgrade。Upgrade 首部字段产生作用的对象仅限于客户端和临近服务器之间。因此,使用首部字段Upgrade时,还需要额外指定Connection: Upgrade 。对于附有 首部字段Upgrade的请求,服务器可用101 Switching Protocols 状态码作为 响应返回。
Via
显示了报文经过的中间节点(代理、网关)
使用Via是为了跟踪客户端和服务器之间的请求/响应路径,避免请求循环以及能够识别请求/响应链中发送者协议的功能。Via 字段由代理服务器添加,不论是正向代理还是反向代理,并且可以出现在请求标头和响应标头中。它用于跟踪消息转发。例如下图所示
Via后面的的1.1, 1.0表示接收服务器.上的HTTP版本,Via首部是为了跟踪路径,经常和TRACE方法一 起使用
通用缓存首部
HTTP/1.0引入了第一个允许HTTP应用程序缓存对象本地副本的首部,这样就不需要总是直接从源端服务器获取了。
Cache-Control
用于随报文传送缓存指示
Pragma
- 另一种随报文传输指示的方式,但并不专用于缓存
- 从技术角度看来,Pragma是一种请求首部,从未被指定于响应首部
Pragma是http 1.1之前版本的历史遗留字段,仅作为与http的向后兼容而定义。它的一-般形式如下
只用于客户端发送的请求中。客户端会要求所有的中间服务器不返回缓存的资源。
如果所有的中间服务器都以实现HTTP /1.1为标准,那么直接使用Cache-Control: no-cache即可,如果不是的话,就要包含两个字段,如下
请求首部
请求首部是请求报文特有的。
信息部首部
它们向服务器提供了一些额外的信息,比如谁发送请求、请求源自与何处等
Accept首部
Accept首部为客户端提供了一种将其喜好和能力告知服务器的方式,包括它们想要什么,可以使用什么,以及它们不想要什么。这样,服务器就可以根据这些额外信息,对要发送的内容做出更明智的决定,就不需要浪费时间和带宽来发送客户端无法使用的东西
比如,下面的Accept首部就用来告知服务器客户端会接收与其请求相符的任意媒体类型:
Accept: */*
条件请求首部
有时客户端希望为请求加上限制。比如,如果客户端已经有了一份文档副本,就希望只在服务器上的文档与客户端拥有的副本有所区别时,才请求服务器传输文档。通过条件请求首部,客户端就可以为请求加上这种限制。要求服务器在对请求进行响应之前,确保某个条件为真。
安全请求首部
HTTP本身就支持一种简单的机制,可以对请求进行质询/响应认证。这种机制要求客户端在获取特定的资源之前,先对自身进行认证,这样就可以使得事务稍微安全一些。
代理请求首部
响应首部
响应首部是响应报文特有的。
信息部首部
响应首部为客户端提供了一些额外信息,比如谁在发送响应、响应者的功能,甚至与响应相关的一些特殊指令。这些首部有助于客户端处理响应,并在将来发起更好的请求。
协商首部
如果资源由多种表示方法—比如,如果服务器上有某文档的法语和德语版本,HTTP/1.1可以为服务器和客户端提供对资源进行协商的能力。
下面列出了几个首部,服务器可以用它们来传递与可协商资源有关的信息。
安全响应首部
同安全请求首部一样,这里本质上是HTTP的质询/响应认证机制的响应测。
实体首部
有很多首部可以用来描述HTTP报文的负荷。由于请求和响应报文中都可能包含实体部分,所以这两种类型的报文中都可能出现这些首部
实体首部提供了有关实体以及其内容的大量信息,从有关对象类型的信息,到能够对资源使用的各种有效的请求方法。总之,实体首部可以告知报文的接受者它在对什么进行处理。
信息部首部
内容首部
内容首部提供了与实体内容有关的特定信息,说明了其类型、尺寸以及处理它所需要的其他有用信息。比如,Web浏览器可以通过查询返回的内容类型,得知如何显示对象。
实体缓存首部
通用的缓存首部说明了如何或者什么时候进行缓存。实体的缓存首部提供了与被缓存实体有关的信息------比如,验证已经缓存的资源副本是否仍然有效所需的信息,以及更好的估计已缓存资源何时失效所需的线索。