如果说HTTP是因特网的信使,那么HTTP报文就是它用来搬东西的包裹了。第
1章说明了HTTP程序是怎样互相发送报文来完成工作的。本章则会介绍所有与
HTTP报文有关的事情一如何 创建报文,以及如何理解它们。通过阅读本章,就
可以了解编写自己的HTTP应用程序所需掌握的大部分内容。具体来说,你会理解
下列概念:
●报文是如何流动的;
●HTTP报文的三个组成部分(起始行、首部和实体的主体部分) ;
●请求和响应报文之间的区别;
●请求报文支持的各种功能(方法)
●和响应报文-起返回的各种状态码;
●各种各样的HTTP首部都是用来做什么的。
3.1
报文流
HTTP报文是在HTTP应用程序之间发送的数据块。这些数据块以一一些文本形式的
元信息(meta-information) 开头,这些信息描述了报文的内容及含义, 后面跟着
可选的数据部分。这些报文在客户端、服务器和代理之间流动。术语“流入”、“流
出”、“上游”及“下游”都是用来描述报文方向的。
3.1.1
报文流入源端服务器
HTTP使用术语流入(inbound) 和流出(outbound) 来描述事务处理(transaction)
的方向。报文流入源端服务器,工作完成之后,会流回用户的Agent代理中(参见
图3-1)。
image.png
3.1.2
报文向下游流动
HTTP报文会像河水一样流动。不管是请求报文还是响应报文,所有报文都会向
下游(downstream) 流动(参见图3-2)。所有报文的发送者都在接收者的上游
(upstream)。在图3-2中,对请求报文来说,代理1位于代理3的上游,但对响应;
报文来说,它就位于代理3的下游。
image.png
3.2
报文的组成部分
HTTP报文是简单的格式化数据块。看一下图3-3给出的例子。每条报文都包含一
条来自客户端的请求,或者一条来自服务器的响应。它们由三个部分组成:对报文
进行描述的起始行(start line)、包含属性的首部(header) 块,以及可选的、包含
数据的主体(body) 部分。
image.png
起始行和首部就是由行分隔的ASCII文本。每行都以一个由两个字符组成的行终止
序列作为结束,其中包括一个回车符(ASCII 码13)和一一个换行符(ASCII 码10)。
这个行终止序列可以写做CRLF。需要指出的是,尽管HTTP规范中说明应该用
CRLF来表示行终止,但稳健的应用程序也应该接受单个换行符作为行的终止。有
些老的,或不完整的HTTP应用程序并不总是既发送回车符,又发送换行符。
实体的主体或报文的主体(或者就称为主体)是一个可选的数据块。与起始行和首
部不同的是,主体中可以包含文本或二进制数据,也可以为空。
在图3-3的例子中,首部给出了一些与主体有关的信息。Content -Type行说明了
主体是什么一一在这 个例子中,就是纯文本文档。Content -Length行说明了主体
有多大,在这里就只有19个字节。
3.2.1
报文的语法
所有的HTTP报文都可以分为两类:请求报文(request message)和响应报文
(response message)。 请求报文会向Web服务器请求-一个动作。响应报文会将请求
的结果返回给客户端。请求和响应报文的基本报文结构相同。图3-4显示了获取一
张GIF图片所需的请求和响应报文。
这是请求报文的格式:
<method> <request -URL> <version>
<headers>
<entity-body>
这是响应报文的格式(注意,只有起始行的语法有所不同) :
<version> <statu8> <reason-phrase>
<headers>
<entity-body>
下面是对各部分的简要描述。
●方法(method)
客户端希望服务器对资源执行的动作。是一个单独的词,比如GET.HEAD或
POST。本章稍后将详细介绍方法。
●请求URL (request-URL)
命名了所请求资源,或者URL路径组件的完整URL。如果直接与服务器进行对
话,只要URL的路径组件是资源的绝对路径,通常就不会有什么问题一-服务
器可以假定自己是URL的主机/端口。第2章详细地介绍了URL的语法。
●版本(version)
报文所使用的HTTP版本,其格式看起来是这样的:
HTTP/ <major>. <minor>
其中主要版本号(major) 和次要版本号(minor) 都是整数。本章稍后会详细说
明HTTP的版本问题。
●状态码(status-code)
这三位数字描述了请求过程中所发生的情况。每个状态码的第- -位数字都用于描
述状态的一般类别(“成功”、 “出错”等)。本章稍后提供了HTTP规范定义的状
态码及其含义的完整列表。
●原因短语(reason-phrase)
数字状态码的可读版本,包含行终止序列之前的所有文本。本章稍后提供了
HTTP规范定义的所有状态码的原因短语示例。原因短语只对人类有意义,因
此,比如说,尽管响应行HTTP/1.0 200 NOT OK和HTTP/1.0 200 OK中原因短;
语的含义不同,但同样都会被当作成功指示处理。
●首部(header)
可以有零个或多个首部,每个首部都包含-一个名字, 后面跟着一个冒号(:), 然
后是一个可选的空格,接着是一个值,最后是一个CRLF。首部是由一个空行
(CRLF)结束的,表示了首部列表的结束和实体主体部分的开始。有些HTTP版
本,比如HTTP/1.1,要求有效的请求或响应报文中必须包含特定的首部。本章
稍后会探讨各种HTTP首部。
● 实体的主体部分(entity-body)
实体的主体部分包含一个由任意数据组成的数据块。并不是所有的报文都包含实
体的主体部分,有时,报文只是以-一个CRLF结束。第15章详述了实体。
图3-5展示了一些假想的请求和响应报文。
3.2.2 起始行
所有的HTTP报文都以-一个起始行作为开始。请求报文的起始行说明了要做些什么。
响应报文的起始行说明发生了什么。
1.请求行
请求报文请求服务器对资源进行一些操作。请求报文的起始行,或称为请求行,包
含了一个方法和-一个请求URL,这个方法描述了服务器应该执行的操作,请求URL
描述了要对哪个资源执行这个方法。请求行中还包含HTTP的版本,用来告知服务
器,客户端使用的是哪种HTTP。
所有这些字段都由空格符分隔。在图3-5a中,请求方法为GET,请求URL为
50|第3章
/test/hi-there.txt,版本为HTTP/1.1。在HTTP/1.0之前,并不要求请求行中包含
HTTP版本号。
2.响应行
响应报文承载了状态信息和操作产生的所有结果数据,将其返回给客户端。响应报
文的起始行,或称为响应行,包含了响应报文使用的HTTP版本、数字状态码,以
及描述操作状态的文本形式的原因短语。
所有这些字段都由空格符进行分隔。在图3-5b中,HTTP版本为HTTP/1.0,状态
码为200 (表示成功),原因短语为OK,表示文档已经被成功返回了。在HTTP/1.0
之前,并不要求在响应中包含响应行。
3.方法
请求的起始行以方法作为开始,方法用来告知服务器要做些什么。比如,在行
“GET /specials/saw-blade.gif HTTP/1.0”中,方法就是GET。
HTTP规范中定义了一组常用的请求方法。比如,GET方法负责从服务器获取-一个
文档,POST方法会向服务器发送需要处理的数据,OPTIONS方法用于确定Web
服务器的-般功能,或者Web服务器处理特定资源的能力。
表3-1描述了7种这样的方法。注意,有些方法的请求报文中有主体,有些则是无
主体的请求。
并不是所有服务器都实现了表3-1列出的所有7种方法。而且,由于HTTP设计得
易于扩展,所以除了这些方法之外,其他服务器可能还会实现-一些自己的请求方法。
这些附加的方法是对HTTP规范的扩展,因此被称为扩展方法。,
4.状态码
方法是用来告诉服务器做什么事情的,状态码则用来告诉客户端,发生了什么事情。
状态码位于响应的起始行中。比如,在行HTTP/1.0 200 OK中,状态码就是200。
客户端向一个HTTP服务器发送请求报文时,会发生很多事情。幸运的话,请求会
成功完成。但你不会总是那么幸运的。服务器可能会告诉你无法找到所请求的资源,
你没有访问资源的权限,或者资源被移到了其他地方。
状态码是在每条响应报文的起始行中返回的。会返回一个数字状态和一个可读的状
态。数字码便于程序进行差错处理,而原因短语则更便于人们理解。
可以通过三位数字代码对不同状态码进行分类。200 到299之间的状态码表示成功。
300到399之间的代码表示资源已经被移走了。400到499之间的代码表示客户端
的请求出错了。500到599之间的代码表示服务器出错了。,
image.png
当前的HTTP版本只为每类状态定义了几个代码。随着协议的发展,HTTP规范中
会正式地定义更多的状态码。如果收到了不认识的状态码,可能是有人将其作为当
前协议的扩展定义的。可以根据其所处范围,将它作为那个类别中一个普通的成员
来处理。
比如,如果收到了状态码515 (在表3-2所列5XX代码的已定义范围之外),就应该
认为这条响应指出了服务器的错误,这是5XX报文的通用类别。
表3-3列出了部分最常见的状态码。本章稍后会详细解释当前在用的所有HTTP状
态码。
5.原因短语
原因短语是响应起始行中的最后一个组件。它为状态码提供了文本形式的解释。比
如,在行HTTP/1.0 200 OK中,OK就是原因短语。
原因短语和状态码是成对出现的。原因短语是状态码的可读版本,应用程序开发者
将其传送给用户,用以说明在请求期间发生了什么情况。
HTTP规范并没有提供任何硬性规定,要求原因短语以何种形式出现。本章稍后列
出了状态码和--些建议使用的原因短语。
6.版本号
版本号会以HTTP/x.y的形式出现在请求和响应报文的起始行中。为HTTP应用程序
提供了--种将自己所遵循的协议版本告知对方的方式。
使用版本号的目的是为使用HTTP的应用程序提供一种线索, 以便互相了解对方的
能力和报文格式。在与使用HTTP 1.1的应用程序进行通信的HTTP 1.2 应用程序应
该知道,它不能使用任何新的1.2特性,因为使用老版本协议的应用程序很可能无
法实现这些特性。
版本号说明了应用程序支持的最高HtTP版本。但HTTP/1.0应用程序在解释包含
HTTP/1.1的响应时,会认为这个响应是个1.1 响应,而实际上这只是响应应用程序
所使用的协议等级,在这些情况下,版本号会在应用程序之间造成误解了。
注意,版本号不会被当作分数来处理。版本中的每个数字(比如HTTP/1.0中的1
和0)都会被当作-一个单独的数字来处理。因此,在比较HTTP版本时,每个数字
都必须单独进行比较,以便确定哪个版本更高。比如,HTTP/2.22 就比HTTP/2.3的
版本要高,因为22比3大。
3.2.3
首部
前一小节的重点是请求和响应报文的第一行(方法、状态码、原因短语和版本号)。
跟在起始行后面的就是零个、一个或多个HTTP首部字段(参 见图3-5)。
HTTP首部字段向请求和响应报文中添加了- - 些附加信息。本质上来说,它们只是-一
些名1值对的列表。比如,下面的首部行会向Content - Length首部字段赋值19:
Content- length: 19
1.首部分类
HTTP规范定义了几种首部字段。应用程序也可以随意发明自己所用的首部。HTTP
首部可以分为以下几类。
●通用首部
既可以出现在请求报文中,也可以出现在响应报文中。
●请求首部
提供更多有关请求的信息。
●响应首部
提供更多有关响应的信息。
●实体首部
描述主体的长度和内容,或者资源自身。
●扩展首部
规范中没有定义的新首部。,
每个HTTP首部都有- -种简单的语法:名字后面跟着冒号( : ),然后跟上可选的空
格,再跟上字段值,最后是一个CRLF。表3-4列出了一些常见的首部实例。
2.首部延续行
将长的首部行分为多行可以提高可读性,多出来的每行前面至少要有一个空格或制
表符(tab)。
例如:
HTTP/1.0 200 OK
Content-Type: image/gif
Content -Length: 8572
Server: Test Server
Version 1.0
在这个例子中,响应报文里包含了一一个Server首部,其值被划分成了多个延续行。
该首部的完整值为Test server Version 1.0。
本章稍后将简要介绍所有的HTTP首部。附录C提供了所有首部更为详细的参考。
3.2.4
实体的主体部分
HTTP报文的第三部分是可选的实体主体部分。实体的主体是HTTP报文的负荷。
就是HTTP要传输的内容。
HTTP报文可以承载很多类型的数字数据:图片、视频、HTML文档、软件应用程
序、信用卡事务、电子邮件等。
3.2.5
版本0.9的报文
HTTP版本0.9是HTTP协议的早期版本。是当今HTTP所拥有的请求及响应报文
的鼻祖,但其协议要简单得多(参见图3-6)。
HTTP/0.9报文也由请求和响应组成,但请求中只包含方法和请求URL,响应中只
包含实体。它没有版本信息(它是第一个,而且是当时唯一-的版本), 没有状态码或
原因短语,也没有首部。
但这种简单协议无法提供更多的灵活性,也无法实现本书中描述的大部分HTTP特
性和应用。这里对其进行简要的描述,是因为仍然有一-些客户端、服务器和其他应,
用程序在使用这个协议,应用程序的编写者应该清楚它的局限性。
3.3
方法
现在,我们对前面在表3-1中列出的-一些基本HTTP方法进行更为深入的讨论。注
意,并不是每个服务器都实现了所有的方法。如果一台服务器要与HTTP 1.1 兼容,
那么只要为其资源实现GET方法和HEAD方法就可以了。
即使服务器实现了所有这些方法,这些方法的使用很可能也是受限的。例如,支持
DELETE方法或PUT方法(本节稍后介绍)的服务器可能并不希望任何人都能够删
除或存储资源。这些限制通常都是在服务器的配置中进行设置的,因此会随着站点
和服务器的不同而有所不同。
3.3.1 安全方法
HTTP定义了一组被称为安全方法的方法。GET方法和HEAD方法都被认为是安全
的,这就意味着使用GET或HEAD方法的HTTP请求都不会产生什么动作。
不产生动作,在这里意味着HTTP请求不会在服务器上产生什么结果。例如,你在
Joe的五金商店购物时,点击了“提交购买”按钮。点击按钮时会提交-一个带有信
用卡信息的POST请求(稍后讨论),那么在服务器上,就会为你执行一个动作。在
这种情况下,为购买行为支付信用卡就是所执行的动作。
安全方法并不一定是什么动作都不执行的(实际上,这是由Web开发者决定的)。
使用安全方法的目的就是允许HTTP应用程序开发者通知用户,什么时候会使用某
个可能引发某些动作的不安全方法。在Joe的五金商店的例子中,你的Web浏览器
可能会弹出一-条警告消息,说明你正在用不安全的方法发起请求,这样可能会在服
务器上引发一些事件(比如用你的信用卡支付费用)。
3.3.2
GET
GET是最常用的方法。通常用于请求服务器发送某个资源。HTTP/1.1 要求服务器
实现此方法。图3-7显示了一个例子,在这个例子中,客户端用GET方法发起了-一
次HTTP请求。
3.3.3
HEAD
HEAD方法与GET方法的行为很类似,但服务器在响应中只返回首部。不会返回实
体的主体部分。这就允许客户端在未获取实际资源的情况下,对资源的首部进行检
查。使用HEAD,可以:
●在不获取资源的情况下了解资源的情况(比如,判断其类型) ;
●通过查看响应中的状态码,看看某个对象是否存在;
●通过查看首部,测试资源是否被修改了。
服务器开发者必须确保返回的首部与GET请求所返回的首部完全相同。遵循
HTTP/1.1规范,就必须实现HEAD方法。图3-8显示了实际的HEAD方法。
3.3.4
PUT
与GET从服务器读取文档相反,PUT方法会向服务器写入文档。有些发布系统允
许用户创建Web页面,并用PUT直接将其安装到Web服务器上去(参见图3-9)。
PUT方法的语义就是让服务器用请求的主体部分来创建一个由所请求的URL命名
的新文档,或者,如果那个URL已经存在的话,就用这个主体来替代它。
因为PUT允许用户对内容进行修改,所以很多Web服务器都要求在执行PUT之
前,用密码登录。在第12章中可以读到更多有关密码认证的内容。
3.3.5
POST
POST方法起初是用来向服务器输入数据的。实际上,通常会用它来支持HTML
的表单。表单中填好的数据通常会被送给服务器,然后由服务器将其发送到它要去
的地方(比如,送到一个服务器网关程序中,然后由这个程序对其进行处理)。图
3-10显示了一个用POST方法发起HTTP请求一向 服务器发送表单数据一-的客
户端。
3.3.6 TRACE
客户端发起一个请求时,这个请求可能要穿过防火墙、代理、网关或其他一-些应用
程序。每个中间节点都可能会修改原始的HTTP请求。TRACE方法允许客户端在,
最终将请求发送给服务器时,看看它变成了什么样子。
TRACE请求会在目的服务器端发起一个“环回”诊断。行程最后- -站的服务器会
弹回一条TRACE响应,并在响应主体中携带它收到的原始请求报文。这样客户端
就可以查看在所有中间HTTP应用程序组成的请求/响应链上,原始报文是否,以
及如何被毁坏或修改过(参见图3-11)。
TRACE方法主要用于诊断:也就是说,用于验证请求是否如愿穿过了请求/响应
链。它也是一种很好的工具,可以用来查看代理和其他应用程序对用户请求所产生
效果。
尽管TRACE可以很方便地用于诊断,但它确实也有缺点,它假定中间应用程序对
各种不同类型请求(不同的方法一GET、 HEAD、POST等)的处理是相同的。
很多HTTP应用程序会根据方法的不同做出不同的事情一-比如,代理可能会将
POST请求直接发送给服务器,而将GET请求发送给另一个HTTP应用程序(比如
Web缓存)。TRACE并不提供区分这些方法的机制。通常,中间应用程序会自行决:
定对TRACE请求的处理方式。
TRACE请求中不能带有实体的主体部分。TRACE响应的实体主体部分包含了响应
服务器收到的请求的精确副本。
3.3.7
OPTIONS
OPTIONS方法请求Web服务器告知其支持的各种功能。可以询问服务器通常支持
哪些方法,或者对某些特殊资源支持哪些方法。(有些服务器可能只支持对一些特殊
类型的对象使用特定的操作)。
这为客户端应用程序提供了一种手段,使其不用实际访问那些资源就能判定访问各
种资源的最优方式。图3-12显示了一个使用OPTIONS方法的请求。
3.3.8
DELETE
顾名思义,DELETE方法所做的事情就是请服务器删除请求URL所指定的资源。
但是,客户端应用程序无法保证删除操作一定会被执行。因为HTTP规范允许服务
器在不通知客户端的情况下撤销请求。图3-13显示了一个DELETE方法实例。
3.3.9.
扩展方法
HTTP被设计成字段可扩展的,这样新的特性就不会使老的软件失效了。扩展方法.
指的就是没有在HTTP/1.1规范中定义的方法。服务器会为它所管理的资源实现一
些HTTP服务,这些方法为开发者提供了一种扩展这些HTTP服务能力的手段。表
3-5列出了一些常见的扩展方法实例。这些方法就是WebDAV HTTP扩展(参见第
19章)包含的所有方法,这些方法有助于通过HTTP将Web内容发布到Web服务
器上去。
并不是所有的扩展方法都是在正式规范中定义的,认识到这一点很重要。 如果你定
义了一个扩展方法,很可能大部分HTTP应用程序都无法理解。同样,你的HTTP
应用程序也可能会遇到一些其他应用程序在用的,而它并不理解的扩"展方法。
在这些情况下,最好对扩展方法宽容一些。如果能够在不破坏端到端行为的情况下
将带有未知方法的报文传递给下游服务器的话,代理会尝试着传递这些报文的。否
则,它们会以501 Not Implemented (无法实现)状态码进行响应。最好按惯例“ 对
所发送的内容要求严. 点,对所接收的内容宽容一些”来处理扩展方法(以及一般
的HTTP扩展)。
网友评论