HTTP 报文是简单的格式化数据块。它们由三个部分组成:
对报文进行描述的起始行(start line); 包含属性的首部(header)块; 可选的、包含数据的主体(body)部分。 起始行和首部就是由行分隔的 ASCII 文本。每行都以一个由两个字符组成的“行终止序列”作为结束,其中包括一个回车符(ASCII 码 13)和一个换行符(ASCII 码 10)。 这个行终止序列可以写做 CRLF。 尽管 HTTP 规范中说明应该用 CRLF 来表示行终止,但稳健的应用程序也应该接受单个换行符作为行的终止。有些老的,或不完整的 HTTP 应用程序并不总是既发送回车符,又发送换行符。 主体是可选的数据块,与起始行和首部不同的是,主体中可以包含文本或二进制数据,也可以为空。
1. 报文的语法
<method> <request-URL > <version > //起始行
<headers > //首部
//空一行
<entity-body > //主体
<version> <status-code > <reason-phrase > //起始行(注意,只有起始行的语法有所不同)
<headers > //首部
//空一行
<entity-body > //主体
各部分简述:
方法(method):客户端希望服务器对资源执行的动作。是一个单独的词,比如 GET、HEAD 或 POST。 请求URL(request-URL):命名了所请求资源,或者 URL 路径组件的完整 URL。如果直接与服务器进行对话,只要 URL 的路径组件是资源的绝对路径,通常就不会有什么问题——服务器可以假定自己是 URL 的主机 / 端口。 版本(version):报文所使用的 HTTP 版本,其格式看起来是这样的HTTP/<major>.<minor>
,其中主要版本号(major)和次要版本号(minor)都是整数。 状态码(status-code):这三位数字描述了请求过程中所发生的情况。每个状态码的第一位数字都用于描述状态的一般类别(“成功”、“出错”等)。 原因短语(reason-phrase):数字状态码的可读版本,包含行终止序列之前的所有文本。原因短语只对人类有意义,因此,比如说,尽管响应行 HTTP/1.0 200 NOT OK 和 HTTP/1.0 200 OK 中原因短语的含义不同,但同样都会被当作成功指示处理。 首部(header):可以有零个或多个首部,每个首部都包含一个名字,后面跟着一个冒号(:),然后是一个可选的空格,接着是一个值,最后是一个 CRLF。首部是由一个空行(CRLF)结束的,表示了首部列表的结束和实体主体部分的开始。有些 HTTP 版本,比如 HTTP/1.1,要求有效的请求或响应报文中必须包含特定的首部。 实体的主体部分(entity-body):实体的主体部分包含一个由任意数据组成的数据块。并不是所有的报文都包含实体的主体部分,有时,报文只是以一个 CRLF 结束。 注意,一组 HTTP 首部总是应该以一个空行(仅有 CRLF)结束,甚至即使没有首部和实体的主体部分也应如此。但由于历史原因,很多客户端和服务器都在没有实体的主体部分时,(错误地)省略了最后的 CRLF。为了与这些流行但不符合规则的实现进行互通,客户端和服务器都应该接受那些没有最后那个 CRLF 的报文。
2. 起始行
所有的 HTTP 报文都以一个起始行作为开始。请求报文的起始行说明了要做些什么。响应报文的起始行说明发生了什么。
1. 请求行
请求报文请求服务器对资源进行一些操作。请求报文的起始行,或称为请求行。 包含了一个方法、一个请求 URL和一个 HTTP 的版本。
方法:描述了服务器应该执行的操作。 请求 URL:描述了要对哪个资源执行这个方法。 HTTP 版本:用来告知服务器,客户端使用的是哪种 HTTP。 所有这些字段都由空格符分隔。 常用7种 HTTP 方法:
方法 描述 是否包含主体 GET 从服务器获取一份文档 否 HEAD 只从服务器获取文档的首部 否 POST 向服务器发送需要处理的数据 是 PUT 将请求的主体部分存储在服务器上 是 TRACE 对可能经过代理服务器传送到服务器上去的报文进行追踪 否 OPTIONS 决定可以在服务器上执行哪些方法 否 DELETE 从服务器上删除一份文档 否
并不是所有服务器都实现了表中列出的所有 7 种方法。而且,由于 HTTP 设计得易于扩展,所以除了这些方法之外,其他服务器可能还会实现一些自己的请求方法。这些附加的方法是对 HTTP 规范的扩展,因此被称为扩展方法。
2. 响应行
响应报文承载了状态信息和操作产生的所有结果数据,将其返回给客户端。响应报文的起始行,或称为响应行。 包含了响应报文使用的 HTTP 版本、数字状态码,以及描述操作状态的文本形式的原因短语。 所有这些字段都由空格符进行分隔。 在 HTTP/1.0 之前,并不要求在响应中包含响应行。 状态码分类:
整体范围 已定义范围 分类 100 ~ 199 100 ~ 101 信息提示 200 ~ 299 200 ~ 206 成功 300 ~ 399 300 ~ 305 重定向 400 ~ 499 400 ~ 415 客户端错误 500 ~ 599 500 ~ 505 服务器错误
* 当前的 HTTP 版本只为每类状态定义了几个代码。随着协议的发展,HTTP 规范中会正式地定义更多的状态码。如果收到了不认识的状态码,可能是有人将其作为当前协议的扩展定义的。可以根据其所处范围,将它作为那个类别中一个普通的成员来处理。
3. HTTP 版本号
版本号会以 HTTP/x.y 的形式出现在请求和响应报文的起始行中。为 HTTP 应用程序提供了一种将自己所遵循的协议版本告知对方的方式。 在与使用 HTTP 1.1 的应用程序进行通信的 HTTP 1.2 应用程序应该知道,它不能使用任何新的 1.2 特性,因为使用老版本协议的应用程序很可能无法实现这些特性。 版本号说明了应用程序支持的最高 HTTP 版本。但 HTTP/1.0 应用程序在解释包含 HTTP/1.1 的响应时,会认为这个响应是个 1.1 响应,而实际上这只是响应应用程序所使用的协议等级,在这些情况下,版本号会在应用程序之间造成误解。http://httpd.apache.org/docs-2.0/misc/known_client_problems.html 上有更多在 Apache 与客户端之间出现 此问题的案例。 注意,版本号不会被当作小数来处理。版本中的每个数字(比如 HTTP/1.0 中的 1 和 0)都会被当作一个单独的数字来处理。因此,在比较 HTTP 版本时,每个数字都必须单独进行比较,以便确定哪个版本更高。比如,HTTP/2.22 就比 HTTP/2.3 的版本要高,因为 22 比 3 大。
3. 首部
跟在起始行后面的就是零个、一个或多个 HTTP 首部字段。 HTTP 首部字段向请求和响应报文中添加了一些附加信息。本质上来说,它们只是一些名 / 值对的列表。
1. 首部分类
HTTP 规范定义了几种首部字段。应用程序也可以随意发明自己所用的首部。HTTP首部可以分为以下几类:
通用首部:既可以出现在请求报文中,也可以出现在响应报文中。 请求首部:提供更多有关请求的信息。 响应首部:提供更多有关响应的信息。 实体首部:描述主体的长度和内容,或者资源自身。 扩展首部:规范中没有定义的新首部。 首部语法:名字后面跟着冒号( :),然后跟上可选的空格,再跟上字段值,最后是一个 CRLF。 常见首部实例:
首部实例 描述 Date:Tue,3Oct 1997 02:16:03 GMT 服务器产生响应的日期 Content-length:15040 实体的主体部分包含了 15040 字节的数据 Content-type:image/gif 实体的主体部分是一个 GIF 图片 Accept: image/gif, image/jpeg, text/html 客户端可以接收GIF图片和JPEG图片以及HTML
2. 首部延续行
将长的首部行分为多行可以提高可读性,多出来的每行前面至少要有一个空格或制表符(tab)。
HTTP/1.0 200 OK
Content-Type: image/gif
Content-Length: 8572
Server: Test Server
Version 1.0
4. 主体
HTTP 报文的第三部分是可选的实体主体部分。实体的主体是 HTTP 报文的负荷,就是 HTTP 要传输的内容。 HTTP 报文可以承载很多类型的数字数据:图片、视频、HTML 文档、软件应用程序、信用卡事务、电子邮件等。
5. HTTP/0.9的报文
HTTP 版本 0.9 是 HTTP 协议的早期版本。是当今 HTTP 所拥有的请求及响应报文的鼻祖,但其协议要简单得多。 HTTP/0.9 报文也由请求和响应组成,但请求中只包含方法和请求 URL,响应中只包含实体。 它没有版本信息(它是第一个,而且是当时唯一的版本),没有状态码或 原因短语,也没有首部。 但这种简单协议无法提供更多的灵活性,也无法实现大部分 HTTP 特性和应用。这里对其进行简要的描述,是因为仍然有一些客户端、服务器和其他应用程序在使用这个协议,应用程序的编写者应该清楚它的局限性。