首页 > 代码库 > Http协议详解

Http协议详解

一、URL与资源

URI是一类更通用的概念,用来表示某一个互联网资源的“位置”。

URI有两个重要的子集:URL和URN。

 

URL语法

URL由三个部分组成:

第一部分:URL方案,告知客户端通过怎样的方式访问资源(如http://,说明要使用HTTP协议)

第二部分:指的是服务器所在的位置(如ip地址或域名,一般也包含了端口号)

第三部分:资源的路径。路径说明了请求的是服务器上的那个资源。

 

大多数URL语法都建立在以下由9个部分构成的通用格式上:

<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>

组件

描述

默认值

<scheme>方案

访问服务器获取资源时是用那种协议(不分大小写)

<user>用户

某些方案访问资源时需要的用户名(如ftp协议)

匿名

<password>密码

用户名后面可能要包含的密码

E-mail地址

<host>主机地址

资源所在服务器的域名或ip地址

<port>端口号

资源所在服务器正在监听的端口号

每个方案都有不同的默认端口号,http方案的默认端口号是80

<path>资源路径

服务器上资源的本地名。路径组件的语法与服务器和方案有关

<params>参数

某些方案会用这个组件指定输入参数,多个参数之间也是用“;”分隔。

<query>查询

用于给动态网页传递参数,可以传递多个参数,用“&”隔开,每个参数的名与值用“=”隔开

<frag>片段

“#”后面的片段是用来“指导浏览器动作的”,对服务端无用,farag也不会被传送到服务器。

下面提一下某些组件的注意事项:

 

参数:

参数由“;”将其与URL其他部分分隔开来(此处的其他部分指的是“参数组件”之前的URL部分,因为其后的部分的分隔符由后面的组件决定)

比如像FTP协议有两种传输模式(二进制和文本形式)。此时就可以通过参数来指定传输形式。

如:ftp://xxx.xx.xx.xx/pub;type=d

其中有一个参数type=d,参数名是type,对应的值时d。

而路径组件可以分为多个路径段,每一个路径段都能有自己的参数组件。如:

http://xxx.xx.xx.xx/hammers;sale=false/index.html;graphics=true

 

片段:

为了应用部分资源内容,可以使用“片段组件”表示资源内部的一个片段。

http://xxx.xx.xx.xx/tools.html#drills如:

浏览器并不会发送#drills,当从服务器拿到html文档并解析后,浏览器会根据片段内容(也就是drills)将页面向下滚动到名为drills的片段处。

 

URL快捷方式

相对URL:

URL有两种方式:相对的和绝对的。

绝对URL包含有访问资源所需的全部信息。

而相对URL则是不完整的,他所缺失的信息要从另一个“基础URL”中推导出来。

 

基础URL来自以下几个地方:

1、在资源中显示提供

有些资源会显式的指定“基础URL”,如,HTML文档可以包含一个定义了基础URL的HTML标记<BASE>

 

2、封装资源的基础URL

 如果一个资源中没有定义显式的基础URL,则相对URL会将“所在资源的URL作为基础URL”

 

将相对URL转换成绝对URL:

保留相对引用中定义的“组件”,然后继承“基础URL”中的剩下的“组件。

 

字符

有些协议(如SMTP协议)在传输的时候,会“剥去”URL中的一些特定的字符,

所以,在设计URL的时候,为了安全起见,我们需要一个“转义机制”,将特殊字符们转义成安全字符。

这种转义方法为:将一个“特殊字符”用一个百分号(%),后面跟着两个表示该字符ASCII码的十六进制数来替换它。

如:字符“~”,ASCII码为126,其十六进制数为0x7E。 所以应该转义成:%7E

http://xxx.xx.xx.xx/~abc即:将URL:

转义为:http://xxx.xx.xx.xx/%7Eabc

 

所有的字符在URL中使用时都应该被转义。(但这并不是强制的,对某些传输协议来说,不转义也不会产生什么问题)。

但某些字符“在作为某些用途时”不用转义,即被保留下来(不过在将其用于保留用途之外的场合时,还是要进行转义)。这些有特殊用途的字符为:

字符

保留用途(该字符用于此用途时,无需转义)

%

作为编码字符的转义标志

/

作为<path>组件的定界符

.

在路径组件中使用

..

在路径组件中使用

#

作为<frag>组件定界符

?

作为<query>组件定界符

;

作为<params>组件定界符

:

作为方案、用户、密码、主机、端口组件的定界符

$+

任何时候都可保留

@&=

在某些方案的上下文中有特殊含义

 

方案

常见的方案格式:

http

超文本传输协议,没有用户组件和密码组件,默认端口为80.

基本格式:

http://<host>:<port>/<path>?<query>#<frag>

 

https

与http方案唯一的区别在于,https方案使用了SSL,SSL为http连接提供了端到端的加密机制。https语法与http相同。默认端口为443.

基本格式:

https://<host>:<port>/<path>?<query>#<frag>

 

mailto

该URL指向的是E-mail地址。mailto URL的格式与标准URL格式不同。具体语法记录在RFC822中。

基本格式:

mailto:<RFC-822-addr-spec>

 

ftp

文本传输协议。用来从FTP服务器上下载或向其上传文件。

基本格式:

ftp://<user>:<password>@<host>:<port>/<path>;<params>

 

rtsp,rtspu

音/视频媒体资源标识符。

rtspu中的u表示它使用的是UDP协议获取资源。

基本格式:

rtsp://<user>:<password>@<host>:<port>/<path>

rtspu://<user>:<password>@<host>:<port>/<path>

 

file

方案file表示一台指定主机上课直接访问的文件。如果省略了主机名,就默认为正在使用URL的本地主机。

基本格式:

file://<host>/<path>

 

news

用来访问一些特定的文章或新闻组。它有一个独特的性质:news URL自身包含的信息不足以对资源进行定位。

new URL中没有提供主机名或机器名。而是需要从用户那里获取此类信息。如 可以在浏览器的选项里指定服务器。

新闻资源可以从多台服务器中获取。被称为位置无关的。

基本格式:

news:<newsgroup>

 

telnet

用于访问交互式业务。他表示的不是资源本身。而是可通过telnet协议访问的交互式应用程序。

基本格式:

telnet://<user>:<password>@<host>:<port>/

 

二、HTTP报文

如果说HTTP是信使,那么HTTP报文就是用来搬东西的包裹了。

HTTP报文由一行行的简单字符串组成。

HTTP报文都是纯文本的,不是二进制代码,读写方便。

HTTP报文只有两种:客户端发送的“请求报文”。服务端发送的“响应报文”。

HTTP报文由三个部分组成:起始行、首部字段、主体。

 

报文流

HTTP使用术语“流入”、“流出”、“上游”、“下游”来描述报文的方向。

如:报文流入服务器后,又会流出回用户的浏览器。

所有的HTTP报文都会向“下游”游动,所有的发送者都在接收者的“上游”。

 

报文的组成

之前提到了,每条报文由三个部分组成:

起始行和首部是由“行”分隔的ASCII文本。

每行以一个“由两个字符组成的行终止序列”作为结束,即:一个回车符(ASCII码13)和一个换行符(ASCII码10)。

(虽然规范中要求用这两种字符表示行终止,但稳健的应用也应该接受单个“换行符”作为行终止。因为有些老HTTP程序可能只会发送个换行符)。

 

报文的语法

所有的报文都能分为两类:请求报文和响应报文。

 

请求报文的格式:

<method> <request-URL> <version>

<headers>

 

<entity-body>

 

响应报文的格式:(只有起始行的语法有所不同)

<version> <status> <reason-phrase>

<headers>

 

<entity-body>

 

对各部分的简要描述(稍后会详细介绍):

方法(method)

客户端希望服务端对资源执行的动作。如:GET、POST等

 

请求URL(request-URL):

完整的URL。

 

版本(version):

报文所使用的HTTP版本,格式为:HTTP/<major>.<minor>

其中主要版本号(major)和次要版本号(minor)都是整数。

 

状态码(status):

这三位数字用于描述请求过程中所发生的情况(如成功、出错等)。

 

原因短语(reason-phrase)

状态码(status)的可读版本,原因短语只对人类有意义,机器不会处理它。

 

首部(headers):

可以有零个或多个首部。每个首部占一行。

每个首部的格式为:先是一个首部名,后面跟一个冒号(:),然后是一个可选的空格,接着是一个值。

在整个首部组结束时,跟一个空行(CR+LF,即回车符+换行符)结束该首部。

 

主体(entity-body):

该部分包含一个由“任意数据组成的数据块”。

并不是所有的报文都有实体部分。

注:虽然规定里首部必须以空行结束。但很多客户端和服务端在没有实体时,(错误的)省略了首部最后的空行。

 

起始行

所有的HTTP报文都是以一个起始行作为开始。

请求报文的起始行说明了要做什么。或称为请求行,包含了一个方法、一个请求URL、HTTP的版本。这些字段都是由空格符分隔。

响应报文的起始行说明了发生了什么。或称为响应行。包含了HTTP的版本、数字状态码、原因短语。这些字段都是由空格符分隔。

 

方法

常用的HTTP方法:

方法

描述

是否包含主体(entity-body)

GET

通常用于请求服务器发送某个资源。

HEAD

只从服务器获取文档的首部。不会返回主体部分。可以用来:1、在不获取资源的情况下了解资源情况。2、通过查看响应中的状态码,查看对象是否存在。3、通过查看首部,测试资源是否被修改。

POST

向服务器发送需要处理的数据。通常用它来支持HTML的表单。

PUT

让服务器通过请求的主体部分创建一个由所请求的URL命名的新文档,或者如果该URL所指资源已经存在,则用这个主体来替换它。由于PUT允许修改内容,所以一般都需要用账户密码登录。

TRACE

客户端发起一个请求可能要穿过防火墙、代理等多个应用。每个中间节点都可能会修改原始HTTP请求。TRACE方法允许客户端看到该请求最终变成了什么样子。即:行程最后一站的服务器会返回一条TRACE响应。

OPTIONS

OPTION方法可以请求服务器告知其支持哪些方法。

DELETE

请求服务器删除URL所指定的资源。但此方法并不一定会被执行。因为HTTP协议允许服务端在不通知客户端的情况下撤销请求。

由上表可知,有些方法的请求报文中并不存在主体。

 

服务器还可以实现一些自己定义的方法。这些方法被称为扩展方法。

常见的扩展方法有:

方法

描述

LOCK

允许用户“锁定”资源。如,可以在编辑某个资源时将其锁定,防止别人同时对其进行修改。

MKCOL

允许用户创建资源

COPY

在服务器上复制资源

MOVE

在服务器上移动资源

 

并不是每个服务器都实现了所有的方法。如HTTP1.1只要求服务器必须实现GET和HEAD方法。

 

 

状态码

状态码存在于响应报文的起始行中,作用是告诉客户端,发生了什么。

状态码分类:

整体范围

目前已定义的范围

分类

100~199

100~101

信息提示

200~299

200~206

成功

300~399

300~305

重定向

400~499

400~415

客户端错误

500~599

500~505

服务端错误

 

100~199:信息性状态码

状态码

原因短语

含义

100

Continue

说明收到了请求的初始部分,请客户端继续。

101

Switching Protocols

说明服务器正在根据客户端的指定,将协议updata首部所列的协议。

 

200~299:成功状态码

状态码

原因短语

含义

200

OK

请求没问题,响应报文的主体部分包含了所请求的资源。

201

Created

用于在服务器上创建对象的请求(如PUT)。由于需要创建的对象已经创建好了。所以返回响应报文的时候应该在实体中包含已创建的资源的URL。

202

Accepted

请求已被接受,但服务器还未执行相关动作。不保证服务器会完成这个请求。

203

Non-Authoritative Information

首部中包含的信息不是来自原端服务器,而是来自资源的一份副本。

204

No Content

响应报文中不包含主体部分。用于浏览器不转为显示新文档的情况下,对其进行更新。

205

ResetContent

负责告诉浏览器,清除当前页面中所有HTML表单元素。

206

Partial Content

成功执行了一个“范围请求”。如客户端通过特殊的首部,来获取某个范围内的文档。

 

300~399:重定向状态码

一般情况下重定向的流程为:

客户端发送请求报文。

服务端返回一个含有“3xx”重定向码的响应报文。

然后客户端根据响应报文的内容,再发送一个请求报文到重定向的服务器。

然后该服务器再返回给客户端响应报文。

状态码

原因短语

含义

300

Multiple

客户端请求一个“实际指向多个资源”的URL时会返回该状态码。返回该状态码时会附带一个选项列表,用户可以选择发希望使用那一项。然后再发送请求进行访问。

301

Moved

客户端请求的URL已被移除,所以该响应报文的Location首部中会含有该资源现在所处的URL。

302

Found

临时重定向。但客户端只是临时使用Location中的重定向URL,将来的请求还是用的是老的URL

303

See Other

HTTP/1.1中使用303来实现与301同样的行为。

304

Not Modified

客户端可以通过首部,将请求变成带有条件的,当客户端发送这种有条件的GET请求获取资源时,而服务器中该资源近期又未被修改,则可以用该状态码返回,表示该资源没被修改,客户端应该展示该资源的本地缓存。也就是说带有该状态码的响应不应该包含主体部分。

305

Use Proxy

用来说明必须通过代理来访问该资源,代理中资源的URL由Location首部给出

307

Temporary Redirect

HTTP/1.1中用307代替了302

 

400~499:客户端错误状态码

状态码

原因短语

含义

400

Bad Request

告知客户端它发送了一个错误的请求

401

Unauthorized

与适当的首部一同返回,要求客户端在获取资源之前先认证。

402

Payment Required

目前未使用,以后可能会使用

403

Forbidden

请求被服务器拒绝了,可以在主体部分对拒绝原因进行描述。

404

Not Found

服务器无法找到被请求的URL。

405

Method Not Allowed

请求报文的首部中的方法服务器不允许。返回次响应报文时,首部里应该包含Allow首部,一遍告知客户端可以使用那些方法。

406

Not Acceptable

客户端可以在URL中指定它愿意接受“什么类型”的实体。而当服务器没有与之相匹配的实体时,可使用此代码

407

Proxy Authentiction Required

与401类似,但用于需要认证的“代理服务器”

408

Request Timeout

为了完成客户端的请求,花费了大量的时间,超时了。

409

Conflict

请求可能会在资源上引发冲突,响应中应该包含描述冲突的主体。

410

Gone

与404类似,现在找不到请求的资源,但以前曾经拥有过。

411

Length Required

服务器要求在请求报文中包含Content-Length首部。

412

Precondition Failed

客户端发起条件请求,且其中一个条件失败了的时候使用。

413

Request Entity Too Large

客户端发送的请求报文中的实体太大了。

414

Request URI Too Long

客户端发送的URL请求过长

415

Unsupported Media Type

服务端无法理解客户端发送的请求报文中实体的内容类型。

416

Request Range Not Satisfiable

请求报文请求的是指定资源的某个范围,而此范围无效时,返回此状态码。

417

Expectation Failed

请求报文的Expect首部中有一个期望,但服务器没法满足该期望时,使用此码。

 

500~599:服务端错误状态码

状态码

原因短语

含义

500

Internal Server Error

服务器遇到一个妨碍它为请求提供服务的错误。

501

Not Implemented

客户端发送的请求超出服务器的能力范围。

502

Bad GateWay

作为代理或网关来使用的服务器无法连接到其父网关。

503

Service Unavailable

用来说明服务器现在无法为请求提供服务,但将来可以。如果服务器知道何时资源可用,则可以在响应报文的首部中包含一个Rety-After首部。

504

Gateway Timeout

此响应来自代理或网关,表示他们在等待其他服务器响应时超时了。

505

HTTP Version Not Supported

服务端收到的请求使用了它不支持的协议版本。

 

以上这些状态码其实不用刻意的去背,只要多留意一下“原因短语”,还是很容易辨识的。

 

原因短语

原因短语与状态码是成对出现的,

HTTP并没有硬性规定什么状态码必须对应什么原因短语,但提倡使用上面提到的原因短语。

 

版本号

版本号会以HTTP/<major>.<minor>的形式出现。目的是以便互相了解对方的能合报文格式。

版本号不会被当作小数来处理。版本中<major>和<minor>会被当做单独的数字来比较与处理。

 

首部

首部和方法配合着工作。共同决定了客户端和服务器能做什么。

一个报文中可以有零个或多个首部。且“同一种首部可以有多个(如一个响应报文首部里可以有多个Set-Cookie首部)”

首部主要分为以下五类:

1、通用首部

这些首部客户端和服务端都可以使用。提供一些最基本的信息。

首部

描述

Connection

允许客户端和服务器指定与连接有关的选项。

Date

提供日期和时间标志,说明报文是什么时间创建的。

MIME-Version

给出发送端使用的MIME版本

Trailer

如果报文采用了分块传输编码方式,可用这个首部列出位于报文拖挂部分的首部集合。

Transfer-Encoding

告知接收端,报文采用了什么编码方式。

Update

给出发送端想要“升级”使用的新协议(如http的升级协议websocket)

Via

显示了报文经过的中间节点(代理、网关)

Cache-Control

随报文传送缓存指示

Pragma

另一种随报文传送指示的方式,但并不专用于传送缓存。

 

2、请求首部

是请求报文特有的首部,服务器可以根据请求首部中的信息,为客户端提供更好的响应。

请求首部又可以细分为以下几种请求首部:

1、请求的信息性首部

首部

描述

Client-IP

提供运行客户端的机器的IP地址

From

客户端用户的E-mail地址

Host

接收该请求的服务器的主机名和端口号

Referer

请求的URL

UA-Color

客户端显示器的显示颜色有关的信息

UA-CPU

客户端CPU的类型或制造商

UA-Disp

客户端显示器能力有关的消息

UA-OS

客户端的操作系统的名称及版本

UA-Pixels

客户端显示器的像素信息

User-Agent

将发起请求的应用程序名称告知服务器(如具体的浏览器,可以根据这个对不同的浏览器进行适配。)

 

2、Accept首部

该首部为客户端提供了一种将其喜好和能力告知服务器的方式,此首部对两方都受益,

客户端会得到它想要的,而服务器也不会浪费宽带发送客户端无法使用的东西。

首部

描述

Accept

告诉服务器能够发送那些媒体类型

Accept-Charset

告诉服务器能够发送那些字符集

Accept-Encoding

告诉服务器能够发送那些编码方式

Accept-Language

告诉服务器能够发送那些语言

TE

告诉服务器可以使用那些扩展传输编码

 

3、条件请求首部

客户端为请求加上某些限制,要求服务端在对请求进行响应之前,确保条件为真。

首部

描述

Expect

允许客户端列出某些所要求的服务器行为

If-Match

如果实体标记与文档当前的实体标记相匹配, 就获取该文档。

If-Modified-Since

除非某个指定日期之后该资源被修改过,否则限制该请求。

If-None-Match

如果提供的实体标记与当前文档的实体标记不相符,就获取文档。

If-Range

允许对文档的某个范围进行条件请求

If-Unmodified-Since

除非某个指定日期之后资源没被修改过,否则限制该请求

Range

如果服务器支持范围请求,就请求资源的指定范围。

 

4、安全请求首部

首部

描述

Authorization

包含了客户端提供给服务器,以便对其自身进行认证的数据

Cookie

客户端想服务端发送的一个令牌(后面会详细的讲cookie)

Cookie2

用来说明请求端支持的cookie版本

 

5、代理请求首部

首部

描述

Max-Forward

在通往源端服务器上的路径上,将请求转发给其他代理或网关的最大次数。

Proxy-Authorization

与Authorization首部相同,但该首部是在代理进行认证时使用。

Proxy-Connection

与Connection首部相同,但该首部是在与代理进行连接时使用。

 

3、响应首部

1、响应的信息性首部

首部

描述

Age

从最初创建开始,响应的持续时间

Public

服务器为其资源支持的请求方法列表

Retry-After

如果资源不可用,则可在此时间重试

Server

服务器应用程序的名称和版本

Title

对HTML文档来说,就是标题

Warning

比原因短语更详细的警告报文

 

2、协商首部

首部

描述

Accept-Ranges

对此资源来说,服务器可接受的范围类型

Vary

这是一个首部列表,服务器会根据该列表挑选最合适资源发送

 

3、安全响应首部

首部

描述

Proxy-Authenticate

来自代理的堆客户端的质询列表

Set-Cookie

可在客户端设置一个令牌,一遍进行标识

Set-Cookie2

与Set-Cookie类似(之后有详解)

WWW-Authenticate

来自服务器的堆客户端的质询列表

 

4、实体首部

实体首部提供了实体及其内容的信息,可以告知报文接收者它在对什么进行处理。

1、实体的信息性首部

首部

描述

Allow

列出了可以对此实体执行的请求方法

Location

告诉客户端该实体“真正的URL”。

 

2、内容首部

首部

描述

Content-Base

基础URL

Content-Encoding

对主体执行的编码方式

Content-Language

理解主体时,最合适的自然语言

Content-Length

主体的长度或尺寸

Content-Location

资源实际所处的位置

Content-MD5

主体的MD5校验和

Content-Range

在整个资源中此实体表示的字节范围

Content-Type

主体的对象类型

 

3、实体缓存首部

提供与被缓存实体有关的信息(之后还会详讲)

首部

描述

ETag

与此实体相关的实体标记

Expires

实体不再有效。需要从原始端源再次获取该实体日期与时间

Last-Modified

该实体最后一次呗修改的日期和时间。

 

5、扩展首部

扩展首部是非标准的首部,可以由开发者自己创建。即使不知道含义,HTTP程序也应该对其进行转发。

 

实体

该部分为可选的。

实体的主体是HTTP要传输的内容。

该内容可以是很多类型的数字数据,如:图片、视频、HTML文档、软件应用程序、电子邮件等。

 

三、cookie机制

http是一种无状态协议。所以一般情况下服务端很难根据http协议来判断访问者是哪一位。

而cookie可以很好的解决这个问题。cookie是当前“识别用户,实现持久会话的最好方式”。

 

cookie的类型

可以笼统的分为两类:会话cookie和持久cookie。

会话cookie:是一种临时cookie,当用户退出浏览器时,会话cookie就删除了

持久cookie:存储在硬盘上,浏览器退出,计算机重启后它任然存在。

 

它们之间的唯一区别就是过期时间。

如果设置了Discard参数,或没有设置Expires或Max-Age参数来扩展过期时间,该cookie就是一个会话cookie

 

cookie的工作原理

某个客户端首次访问服务器时,服务器通过响应首部Set-Cookie或Set-Cookie2,给该客户端“贴上”一个“该客户端独有的cookie”。

这样服务端以后就能根据该cookie来识别客户端了。

浏览器会记住从服务器返回的响应首部中的cookie内容,并将cookie内容存入浏览器的“cookie数据库中”。将来如果用户使用该浏览器访问同一服务器时,浏览器就会挑出“该服务器贴到用户上的那些cookie”,然后通过请求首部Cookie将cookie内容发送给服务器。

 

客户端侧状态

不同的浏览器会以不同的方式存储cookie。

1、IE浏览器

IE将每个cookie都存储在缓存目录里的独立文件中(即每个浏览器“贴的”cookie都对应一个cookie)。

2、谷歌浏览器

将所有的cookie都保存在同一的一个文件里。该文件的格式为SQLite3数据库格式的文件。文件名为Cookies

3、火狐浏览器

将所有的cookie都保存在同一的一个文件里。该文件的格式为SQLite3数据库格式的文件。文件名为cookies.sqlite

 

cookie成分

cookie规范定义在报文的首部里,同一种首部可以重复

如服务器可以在响应报文中设置多个Set-Cookie首部,一次性给浏览器“贴”多个cookie

目前的cookie规范有两个版本。

cookies版本0

http://home.netscape.com/newsref/std/cookie_spec.html描述文档地址:

版本0的响应首部Set-Cookie

格式:

Set-Cookie:name=value [; expires=date] [; path=path] [; domain=domain] [; secure]

其中:Set-Cookie首部有一个强制的cookie值和名。后面的属性都是可选的,由分号隔开。

Set-Cookie属性

描述及实例

name=value

强制的。name和value都是字符序列。除非包含在双引号里,否则不包含分号、逗号、等号、空格。在浏览器后续对服务器的访问中会将其送回Web服务器

expires=date

可选的。该属性会指定一个日期字符串,用来定义cookie的实际生存期。一旦超过日期,浏览器就不再存储cookie了。如果没有指定Expires,cookie会在浏览器关闭时过期。date格式为:Weekday(如Wednesday), DD-Mon-YY HH:MM:SS GMT

path=path

可选的。该属性可以为服务器上的特定文档分配cookie。(路径“/”与域名中所有内容相匹配)。默认为“产生Set-Cookie响应的URL路径”

domain=domain

可选的。浏览器只向指定域中的服务器主机名发送cookie。这样服务器就将cookie限制在了特定域中。如:acmc.com域与an.acmc.com相匹配。.com与acmc.com相匹配。如果没有指定域,就默认域为产生Set-Cookie响应的服务器的主机名。

secure

可选的,如果包含此属性,就只有在使用在HTTP使用SSL安全连接时才会发送cookie

 

版本0的请求首部Cookie

客户端发送请求时,会将所有与域、路径、过滤器相匹配且未过期的cookie键值对都发送给该站点。

格式为:

Cookie: name1=value1 [; name2=value2]·····

 

cookies版本1

http://www.ietf.org/rfc/rfc2965.txt描述文档地址:

cookies版本1是cookie的一个扩展版本。虽然该版本引入了新首部,但也能与版本0交互。

主要改动如下:

1、为每个cookie关联上解释性文本,对其目的进行解释。

2、允许在浏览器退出时,不考虑过期时间,将cookie销毁。

3、Max-Age使用相对秒数。

4、在域和路径的基础上还增加了端口号

5、通过cookie首部回送“域、端口、路径过滤器”(如果有的话)

6、为实现互操作性使用的版本号。

7、在Cookie首部从名字中区分出附加关键字的$前缀。

 

版本1的Cookie2首部:

版本1增加了一个cookie2首部,cookie可以告诉服务器:客户端所支持的新的cookie标准版本。

如:Cookie2: $Version="1"

 

四、HTTPS

https方案

https是最常见的http安全版本。

HTTPS就是在安全的传输层上发送HTTP。在将http发送给TCP之前,现将其发送给一个安全层对其进行加密,然后再发送给TCP传输层。

其中安全层使用的协议是SSL或TLS协议。

 

如果URL的方案为https,客户端就会打开一条到服务器端口443(默认情况下)的连接,然后与服务器“握手”,以二进制格式与服务器交换一些SSL安全参数,附上加密的HTTP命令。

 

在未加密HTTP中:

客户端会打开一条到web服务器端口80的TCP连接,发送一条请求报文,接收一条响应报文,关闭连接。

在HTTPS中:

1、客户端首先打开一条到Web服务器端口443的连接。

2、然后建立端口443的TCP连接。之后客户端与服务端进行SSL握手,即对加密参数进行沟通,并交换秘钥。

3、然后SSL初始化就完成了,客户端就可以将请求报文发送给“安全层让其进行加密”。

4、之后在将已加密的请求发送给TCP。

5、然后服务端再将响应发送给SSL层进行加密,加密后再发给TCP,然后发给客户端。

6、SSL关闭,TCP连接关闭。

 

SSL握手

在上面的第二步中,客户端和服务端进行了一次SSL握手。该握手主要完成以下工作:

交换协议版本号。

选择一个两端都了解的密码。

对两端的身份进行验证。

生成临时的会话秘钥,以便加密信道。

 

OpenSSL

SSL是个复杂的二进制协议。我们可以借助一些商业或开源库,来编写SSL客户端和服务端。

OpenSSL是一个实现了SSL和TLS协议以及以及一个全功能的通用加密库。

(之前我的“深入理解Connector”博客中就提到了tomcat native技术中就集成了OpenSSL)

 

可以从http://www.openssl.org上获取OpenSSL的相关信息,并下载。

 

五、实体和编码

各种媒体对象都可以通过http传送,如图像、文本、影音、软件等。HTTP还会确保它的报文被正确的传送、识别、以及适当的处理。

如果说HTTP报文是箱子,那么实体就是货物。

实体包含两个部分:实体首部和实体主体。

 

实体首部

在之前讲解首部的时候列出过HTTP实体首部。在此就不一一列出了。

下面详细的讲一下其中几个实体首部:

Content-Length首部详解

该首部指出实体主体的字节大小。

除非使用了“分块编码”,否则必须使用该首部。

因为该首部会被用来“检测报文结尾”,即用来识别是否传送了完整的报文实体主体。

而且Content-Length在持久连接中也是必不可少的。因为如果是持久连接传送,客户端可通过该首部知道该报文何时结束,也就能知道吓一跳报文何时开始。

 

Content-Length指的长度一定是“实体主体内容编码后的字节长度”。(而不是原始的字节长度)

 

Content-MD5首部详解

该首部发送的是“编码前”的实体主体运行md5算法的结果。

作用是验证端到端实体的完整性,即两边都做一下md5算法,比对一下结果。

另一个作用是充当散列表的关键字,用来快速定位文档。

 

Content-Type首部详解

该首部字段说明了实体主体的基本媒体类型,常用的媒体类型如下表:

媒体类型

描述

text/html

实体主体是HTML文档

text/plain

实体主体是纯文本文档

image/gif

主体是GIF图像

image/jpeg

主体是JPEG格式图像

audio/x-wav

主体包含WAV格式声音数据

model/vrml

主体是三维的VRML模型

application/vnd.ms-powerpoint

主体ppt文档

multipart/byteranges

主体有若干部分,每部分都包含了完整文档中不同的字节范围。

message/http

实体主体包含完整的HTTP报文。

注:该首部说明的是原始实体主体的类型,即主体编码之前的。

 

Content-Encoding首部详解

http应用有时在发送报文前,要对报文中的实体主体进行编码。目的可能是压缩或加密等。

Content-Encoding首部是用来说明编码时使用的算法

内容编码类型:

Content-Encoding值

描述

gzip

实体采用GNUzip编码(效率最高,使用最广)

compress

实体采用Unix的文件压缩程序

deflate

实体采用zlib格式压缩

identity

没有对实体进行编码(默认情况)

 

Accept-Encoding首部详解

毫无疑问,我们不希望服务器用一种客户端无法解析的方法来进行编码。

所以客户端可以通过该首部将自己支持的实体主体编码格式发给服务端。

客户端可以为每种编码附带Q值说明编码优先级。范围是0.0~1.0,1.0表示最希望使用的编码。

“*”表示任何其他方法。

 

传输编码

之前讨论的都是内容编码,主要是对实体主体进行编码。

而传输编码主要是为了改变数据在网络中的传输方式,下面主要说一下传输编码中的分块编码。

 

分块编码把“报文”分割陈若干个大小的块。块之间是紧挨着发送的,这样就不需要使用Content-Length首部了(因为每块的大小都是固定的,只需要知道块数即可)。

注意:分块编码是对整个传输进行编码,而不仅仅是对实体主体进行编码。

 

分块编码有起始的HTTP响应首部开始组成一块,随后就是一系列分块。

每个分块包含一个“长度值”和一个“该分块的数据”。长度值是16进制,数据大小是以字节计算。

长度值与分块之间由“<CR><LF>”分割(之前提到过,这个分割符就是一个回车符(ASCII码13)和一个换行符(ASCII码10))。

最后一个块比较特别,其长度为0,表示主体结束。

 

传输编码的规则:

1、传输编码集合中必须包含“分块”。唯一例外是使用关闭连接来结束报文。

2、当使用分块传输编码时,它必须是最后一个作用在主体之上的(如报文既有内容主体编码,又有分块编码。那么就必须先对实体主体进行内容编码,然后再对整个报文进行分块编码)。

3、分块编码不能多次作用在一个报文主体上。

 

所有的HTTP/1.1程序都支持分块编码。

 

范围请求

http允许客户端只请求文档的某一范围。

 

使用的自然就是我们之前提到的Range响应首部。

如:Range: bytes=4000-

这就表示,客户端只想请求文档开头4000个字节之后的部分。

 

另外还能用该首部来加速下载。

如客户端从多台服务器上下载同一个文档,那么就能“在一条请求报文中”同时从不同服务器上下载该文档的不同范围。返回的响应也是单个实体。

Http协议详解