文章同步于 Github blog
报文流(The Flow of Messages)
HTTP 报文是在 HTTP 应用程序之间发送的数据块。这些数据块以一些文本形式的 元信息(meta-information)
开头,这些信息描述了报文的内容及含义,后面跟着可选的数据部分。
HTTP 使用术语 流入(inbound) 和 流出(outbound) 来描述事务处理(transaction) 的方向。报文流入源端服务器,工作完成之后,会流回用户的 Agent 代理中。
HTTP 报文会像河水一样流动。不管是请求报文还是响应报文,所有报文都会向 下游(downstream)流动。所有报文的发送者都在接收者的上游 (upstream)。
报文的语法(Message Syntax)
HTTP 报文是简单的格式化数据块。每条报文都包含一条来自客户端的请求,或者一条来自服务器的响应。它们由三个部分组成:对报文进行描述的 起始行(start line)
、包含属性的 首部(header)
块,以及可选的包含数据的 主体(body)
部分。
HTTP-message = start-line
*( header-field CRLF )
CRLF
[ message-body ]
报文分类与格式
所有的HTTP报文都可以分为两类:请求报文(request message)
和 响应报文 (response message)
。请求和响应报文的基本报文结构相同。
请求报文的格式:
<method> <request-URL> <version>
<headers>
<entity-body>
响应报文的格式(注意,只有起始行的语法有所不同):
<version> <status> <reason-phrase>
<headers>
<entity-body>
起始行和首部就是由行分隔的 ASCII 文本。每行都以一个由两个字符组成的行终止序列作为结束,其中包括一个回车符(ASCII 码 13)和一个换行符(ASCII 码 10)。 这个行终止序列可以写做 CRLF。
响应报文示例
curl -i www.baidu.com/index.html
HTTP/1.1 200 OK
Server: bfe/1.0.8.18
Date: Wed, 04 Apr 2018 02:39:19 GMT
Content-Type: text/html
Content-Length: 2381
Last-Modified: Mon, 23 Jan 2017 13:27:56 GMT
Connection: Keep-Alive
ETag: "588604dc-94d"
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Pragma: no-cache
Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
Accept-Ranges: bytes
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn"></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登录</a>');</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>©2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必读</a> <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a> 京ICP证030173号 <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>
起始行(Start Lines)
所有的 HTTP 报文都以一个起始行作为开始。请求报文的起始行说明了要做些什么。
响应报文的起始行说明发生了什么。
请求行(Request line)
请求报文请求服务器对资源进行一些操作。请求报文的起始行,或称为请求行,包含了一个方法和一个请求 URL,还包含 HTTP 的版本。所有这些字段都由空格符分隔。
响应行(Response line)
响应报文承载了状态信息和操作产生的所有结果数据,将其返回给客户端。响应报文的起始行,或称为响应行,包含了响应报文使用的 HTTP 版本、数字状态码,以 及描述操作状态的文本形式的原因短语。
方法(Methods)
请求的起始行以方法作为开始,方法用来告知服务器要做些什么。比如,在行 “GET /specials/saw-blade.gif HTTP/1.0”中,方法就是 GET。
状态码 (Status codes)
状态码是在每条响应报文的起始行中返回的。会返回一个数字状态和一个可读的状态。数字码便于程序进行差错处理,而原因短语则更便于人们理解。方法是用来告诉服务器做什么事情的,状态码则用来告诉客户端,发生了什么事情。
整体范围 | 已定义范围 | 分类 |
---|---|---|
100 ~ 199 | 100 ~ 101 | 信息提示 |
200~299 | 200~206 | 成功 |
300 ~ 399 | 300 ~ 305 | 重定向 |
400 ~ 499 | 400 ~ 415 | 客户端错误 |
500 ~ 599 | 500 ~ 505 | 服务器错误 |
原因短语 (Reason phrases)
原因短语是响应起始行中的最后一个组件。它为状态码提供了文本形式的解释。比如,在行 HTTP/1.0 200 OK 中,OK 就是原因短语。
版本号(Version numbers)
版本号会以 HTTP/x.y 的形式出现在请求和响应报文的起始行中。
首部
跟在起始行后面的就是零个、一个或多个 HTTP 首部字段。
HTTP 首部字段向请求和响应报文中添加了一些附加信息。本质上来说,它们只是一些名 / 值对的列表。
首部分类
HTTP 规范定义了几种首部字段。应用程序也可以随意发明自己所用的首部。HTTP 首部可以分为以下几类。
- 通用首部(General headers):既可以出现在请求报文中,也可以出现在响应报文中。
- 请求首部(Request headers):提供更多有关请求的信息。
- 响应首部(Response headers):提供更多有关响应的信息。
- 实体首部(Entity headers):描述主体的长度和内容,或者资源自身。
- 扩展首部(Extension headers):规范中没有定义的新首部。
每个 HTTP 首部都有一种简单的语法:名字后面跟着冒号( :),然后跟上可选的空格,再跟上字段值,最后是一个 CRLF。
实体的主体部分(Entity Bodies)
HTTP 报文的第三部分是可选的实体主体部分。实体的主体是 HTTP 报文的负荷。 就是 HTTP 要传输的内容。
HTTP 报文可以承载很多类型的数字数据:图片、视频、HTML 文档、软件应用程 序、信用卡事务、电子邮件等。
起始行——方法
现在,我们对一些基本 HTTP 方法进行更为深入的讨论。
GET
GET 是最常用的方法。通常用于请求服务器发送某个资源。HTTP/1.1 要求服务器 实现此方法。
HEAD
HEAD 方法与 GET 方法的行为很类似,但服务器在响应中只返回首部。不会返回实体的主体部分。这就允许客户端在未获取实际资源的情况下,对资源的首部进行检查。使用 HEAD,可以:
- 在不获取资源的情况下了解资源的情况(比如,判断其类型);
- 通过查看响应中的状态码,看看某个对象是否存在;
- 通过查看首部,测试资源是否被修改了
PUT
与 GET 从服务器读取文档相反,PUT 方法会向服务器写入文档。有些发布系统允 许用户创建 Web 页面,并用 PUT 直接将其安装到 Web 服务器上去。
PUT 方法的语义就是让服务器用请求的主体部分来创建一个由所请求的 URL 命名的新文档,或者,如果那个 URL 已经存在的话,就用这个主体来替代它。
因为 PUT 允许用户对内容进行修改,所以很多 Web 服务器都要求在执行 PUT 之前,用密码登录。
POST
POST 方法起初是用来向服务器输入数据的。实际上,通常会用它来支持 HTML 的表单。表单中填好的数据通常会被送给服务器,然后由服务器将其发送到它要去的地方。
POST 用于向服务器发送数据。PUT 用于向服务器上的资源(例如文件)中存储数据。
TRACE
客户端发起一个请求时,这个请求可能要穿过防火墙、代理、网关或其他一些应用 程序。每个中间节点都可能会修改原始的 HTTP 请求。TRACE 方法允许客户端在最终将请求发送给服务器时,看看它变成了什么样子。
TRACE 请求会在目的服务器端发起一个“环回”诊断
。行程最后一站的服务器会 弹回一条 TRACE 响应
,并在响应主体中携带它收到的原始请求报文。这样客户端就可以查看在所有中间 HTTP 应用程序组成的请求 / 响应链上,原始报文是否,以 及如何被毁坏或修改过。
TRACE 方法主要用于诊断;也就是说,用于验证请求是否如愿穿过了请求 / 响应 链。它也是一种很好的工具,可以用来查看代理和其他应用程序对用户请求所产生效果。
TRACE 请求中不能带有实体的主体部分。TRACE 响应的实体主体部分包含了响应服务器收到的请求的精确副本。
OPTIONS
OPTIONS 方法请求 Web 服务器告知其支持的各种功能。可以询问服务器通常支持 哪些方法,或者对某些特殊资源支持哪些方法。(有些服务器可能只支持对一些特殊 类型的对象使用特定的操作)。
这为客户端应用程序提供了一种手段,使其不用实际访问那些资源就能判定访问各种资源的最优方式。
DELETE
顾名思义,DELETE 方法所做的事情就是请服务器删除请求 URL 所指定的资源。 但是,客户端应用程序无法保证删除操作一定会被执行。因为 HTTP 规范允许服务 器在不通知客户端的情况下撤销请求。
扩展方法
HTTP 被设计成字段可扩展的,这样新的特性就不会使老的软件失效了。扩展方法指的就是没有在 HTTP/1.1 规范中定义的方法。服务器会为它所管理的资源实现一些 HTTP 服务,这些方法为开发者提供了一种扩展这些 HTTP 服务能力的手段。
首部
首部和方法配合工作,共同决定了客户端和服务器能做什么事情。
通用首部——信息性首部
有些首部提供了与报文相关的最基本的信息,它们被称为通用首部。
Connection
允许客户端和服务器指定与请求 / 响应连接有关的选项
Date
提供日期和时间标志,说明报文是什么时间创建的
MIME-Version
给出了发送端使用的 MIME 版本
Trailer
如果报文采用了分块传输编码(chunked transfer encoding)方式,就可 以用这个首部列出位于报文拖挂(trailer)部分的首部集合
Transfer-Encoding
告知接收端为了保证报文的可靠传输,对报文采用了什么编码方式
Update
给出了发送端可能想要“升级”使用的新版本或协议
Via
显示了报文经过的中间节点(代理、网关)
通用首部——缓存首部
Cache-Control
用于随报文传送缓存指示
Pragma
另一种随报文传送指示的方式,但并不专用于缓存
请求首部——信息性首部
Client-IP
提供了运行客户端的机器的 IP 地址
From
提供了客户端用户的 E-mail 地址
Host
给出了接收请求的服务器的主机名和端口号
Referer
提供了包含当前请求 URI 的文档的 URL
UA-Color
提供了与客户端显示器的显示颜色有关的信息
UA-CPU
给出了客户端 CPU 的类型或制造商
UA-Disp
提供了与客户端显示器(屏幕)能力有关的信息
UA-OS
给出了运行在客户端机器上的操作系统名称及版本
UA-Pixels
提供了客户端显示器的像素信息
User-Agent
将发起请求的应用程序名称告知服务器
请求首部——Accept首部
Accept 首部为客户端提供了一种将其喜好和能力告知服务器的方式。
Accept
告诉服务器能够发送哪些媒体类型
Accept-Charset
告诉服务器能够发送哪些字符集
Accept-Encoding
告诉服务器能够发送哪些编码方式
Accept-Language
告诉服务器能够发送哪些语言
TE
告诉服务器可以使用哪些扩展传输编码
请求首部——条件请求首部(Conditional request headers)
有时客户端希望为请求加上某些限制。
比如,如果客户端已经有了一份文档副本, 就希望只在服务器上的文档与客户端拥有的副本有所区别时,才请求服务器传输文档。通过条件请求首部,客户端就可以为请求加上这种限制,要求服务器在对请求进行响应之前,确保某个条件为真。
Expect
允许客户端列出某请求所要求的服务器行为
If-Match
如果实体标记与文档当前的实体标记相匹配,就获取这份文档
If-Modified-Since
除非在某个指定的日期之后资源被修改过,否则就限制这个请求
If-None-Match
如果提供的实体标记与当前文档的实体标记不相符,就获取文档
If-Range
允许对文档的某个范围进行条件请求
If-Unmodified-Since
除非在某个指定日期之后资源没有被修改过,否则就限制这个请求
Range
如果服务器支持范围请求,就请求资源的指定范围
请求首部——安全请求首部
HTTP 本身就支持一种简单的机制,可以对请求进行质询 / 响应认证。这种机制要 求客户端在获取特定的资源之前,先对自身进行认证,这样就可以使事务稍微安全 一些。
Authorization
包含了客户端提供给服务器,以便对其自身进行认证的数据
Cookie
客户端用它向服务器传送一个令牌——它并不是真正的安全首部,但确实隐含了安全功能。
Cookie2
用来说明请求端支持的 cookie 版本
请求首部——代理请求首部
随着因特网上代理的普遍应用,人们定义了几个首部来协助其更好地工作。
Max-Forward
在通往源端服务器的路径上,将请求转发给其他代理或网关的最大次数——与 TRACE 方法一同使用
Proxy-Authorization
与 Authorization 首部相同,但这个首部是在与代理进行认证时使用的
Proxy-Connection
与 Connection 首部相同,但这个首部是在与代理建立连接时使用的
响应首部——信息性首部
Age
(从最初创建开始)响应持续时间
Public
服务器为其资源支持的请求方法列表
Retry-After
如果资源不可用的话,在此日期或时间重试
Server
服务器应用程序软件的名称和版本
Title
对 HTML 文档来说,就是 HTML 文档的源端给出的标题
Warning
比原因短语中更详细一些的警告报文
响应首部——协商首部(Negotiation headers)
如果资源有多种表示方法——比如,如果服务器上有某文档的法语和德语译稿, HTTP/1.1 可以为服务器和客户端提供对资源进行协商的能力。
Accept-Ranges
对此资源来说,服务器可接受的范围类型
Vary
服务器查看的其他首部的列表,可能会使响应发生变化;也就是说,这是一个首部列表,服务器会根据这些首部的内容挑选出最适合的资源版本发 送给客户端
响应首部——安全响应首部(Response security headers)
我们已经看到过安全请求首部了,本质上这里说的就是 HTTP 的质询 / 响应认证机制的响应侧。
Proxy-Authenticate
来自代理的对客户端的质询列表
Set-Cookie
不是真正的安全首部,但隐含有安全功能;可以在客户端设置一个令牌,
以便服务器对客户端进行标识
Set-Cookie2
与 Set-Cookie 类似,RFC 2965 Cookie 定义
WWW-Authenticate
来自服务器的对客户端的质询列表
实体首部——信息性首部
Allow
列出了可以对此实体执行的请求方法
Location
告知客户端实体实际上位于何处;用于将接收端定向到资源的(可能是新的)位置(URL)上去
实体首部——内容首部(Content headers)
内容首部提供了与实体内容有关的特定信息,说明了其类型、尺寸以及处理它所需 的其他有用信息。比如,Web 浏览器可以通过查看返回的内容类型,得知如何显示对象。
Content-Base
解析主体中的相对 URL 时使用的基础 URL
Content-Encoding
对主体执行的任意编码方式
Content-Language
理解主体时最适宜使用的自然语言
Content-Length
主体的长度或尺寸
Content-Location
资源实际所处的位置
Content-MD5
主体的 MD5 校验和
Content-Range
在整个资源中此实体表示的字节范围
Content-Type
这个主体的对象类型
实体首部——实体缓存首部
通用的缓存首部说明了如何或什么时候进行缓存。实体的缓存首部提供了与被缓存 实体有关的信息——比如,验证已缓存的资源副本是否仍然有效所需的信息,以及 更好地估计已缓存资源何时失效所需的线索。
ETag
与此实体相关的实体标记
Expires
实体不再有效,要从原始的源端再次获取此实体的日期和时间
Last-Modified
这个实体最后一次被修改的日期和时间
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。