HTTP协议

HTTP一直在身边,可是从来没有系统的去学习过这方面的知识,后面要做Http Server,先进行必要的知识补充。


1. 引言

HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。目前在WWW中使用的是HTTP/1.1。

HTTP协议的主要特点可概括如下:

  • 支持客户/服务器模式。
  • 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
  • 灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
  • 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
  • 无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

2. URL

URL(Uniform Resource Locator) 地址用于描述一个网络上的资源。

  • 格式:schema://host[:port#]/path/…/[;url-params][?query-string][#anchor]
参数 说明
scheme 指定低层使用的协议(例如:http, https, ftp)
host HTTP服务器的IP地址或者域名
port# HTTP服务器的默认端口是80
path 访问资源的路径
url-params url参数
query-string 发送给http服务器的数据
anchor-

示例:

1
2
3
4
5
6
Schema: http
host: www.mywebsite.com
path: /sj/test
URL params: id=8079
Query String: name=sviergn&x=true
Anchor: stuff

2.1 HTTP URL

http表示要通过HTTP协议来定位网络资源;host表示合法的Internet主机域名或者IP地址;port指定一个端口号,为空则使用缺省端口80;abs_path指定请求资源的URI;如果URL中没有给出abs_path,那么当它作为请求URI时,必须以“/”的形式给出,通常这个工作浏览器自动帮我们完成。

示例

扩展介绍

URI,是uniform resource identifier,统一资源标识符,用来唯一的标识一个资源。而URL是uniform resource locator,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。而URN,uniform resource name,统一资源命名,是通过名字来标识资源,比如mailto:java-net@java.sun.com。也就是说,URI是以一种抽象的,高层次概念定义统一资源标识,而URL和URN则是具体的资源标识的方式。URL和URN都是一种URI。


3. 消息格式

HTTP消息由客户端到服务器的请求和服务器到客户端的响应组成。
请求消息和响应消息都是由开始行(对于请求消息,开始行就是请求行;对于响应消息,开始行就是状态行),消息报头(可选),空行(只有CRLF的行),消息正文(可选)组成。

请求报文格式

响应报文格式


4. 开始行

4.1 请求消息——请求行

  • 格式:Request-method Request-URI HTTP-Version CRLF

其中,Request-method表示请求方法;Request-URI是一个统一资源标识符;HTTP-Version表示请求的HTTP协议版本;CRLF表示回车和换行(除了作为结尾的CRLF外,不允许出现单独的CR或LF字符)。

请求方法 说明
GET 请求获取Request-URI所标识的资源
POST 在Request-URI所标识的资源后附加新的数据
HEAD 请求获取由Request-URI所标识的资源的响应消息报头
PUT 请求服务器存储一个资源,并用Request-URI作为其标识
DELETE 请求服务器删除Request-URI所标识的资源
TRACE 请求服务器回送收到的请求信息,主要用于测试或诊断
CONNECT 保留将来使用
OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求

示例:

  • GET方法:在浏览器的地址栏中输入网址的方式访问网页时,浏览器采用GET方法向服务器获取资源,例:GET /form.html HTTP/1.1。

  • POST方法:要求被请求服务器接受附在请求后面的数据,常用于提交表单。

1
2
3
4
5
6
7
8
9
POST /reg.jsp HTTP/ (CRLF)
Accept:image/gif,image/x-xbit,... (CRLF)
...
HOST:www.guet.edu.cn (CRLF)
Content-Length:22 (CRLF)
Connection:Keep-Alive (CRLF)
Cache-Control:no-cache (CRLF)
(CRLF) //该CRLF表示消息报头已经结束,在此之前为消息报头
user=jeffrey&pwd=1234 //此行以下为提交的数据,即消息正文

4.2 响应消息——状态行

  • 格式:HTTP-Version Status-Code Reason-Phrase CRLF

其中,HTTP-Version表示服务器HTTP协议的版本;Status-Code表示服务器发回的响应状态代码;Reason-Phrase表示状态代码的文本描述。

响应状态码 说明
1xx 指示信息:表示请求已接收,继续处理
2xx 成功:表示请求已被成功接收、理解、接受
3xx 重定向:要完成请求必须进行更进一步的操作
4xx 客户端错误:请求有语法错误或请求无法实现
5xx 服务器端错误:服务器未能实现合法的请求
常见响应状态码 状态描述 说明
200 OK 客户端请求成功
400 Bad Request 客户端请求有语法错误,不能被服务器所理解
401 Unauthorized 请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden 服务器收到请求,但是拒绝提供服务
404 Not Found 请求资源不存在
500 Internal Server Error 服务器发生不可预期的错误
503 Server Unavailable 服务器当前不能处理客户端的请求,一段时间后可能恢复正常

示例:

  • HTTP/1.1 200 OK (CRLF)

5. 消息报头

HTTP消息报头包括普通报头、请求报头、响应报头、实体报头。
每一个报头域都是由名字+“:”+空格+值组成,消息报头域的名字是大小写无关的。

5.1 普通报头

在普通报头中,有少数报头域用于所有的请求和响应消息,但并不用于被传输的实体,只用于传输的消息。

示例:

  • Cache-Control:用于指定缓存指令,缓存指令是单向的(响应中出现的缓存指令在请求中未必会出现),且是独立的(一个消息的缓存指令不会影响另一个消息处理的缓存机制),HTTP1.0使用的类似的报头域为Pragma。
    请求时的缓存指令包括:no-cache(用于指示请求或响应消息不能缓存)、no-store、max-age、max-stale、min-fresh、only-if-cached;响应时的缓存指令包括:public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age、s-maxage。为了指示IE浏览器(客户端)不要缓存页面,服务器端的JSP程序可以编写如下:response.setHeader(“Cache-Control”,”no-cache”)。这句代码将在发送的响应消息中设置普通报头域:Cache-Control:no-cache。

  • Date:表示消息产生的日期和时间。

  • Connection:允许发送指定连接的选项。例如指定连接是连续,或者指定“close”选项,通知服务器,在响应完成后,关闭连接。

5.2 请求报头

请求报头允许客户端向服务器端传递请求的附加信息以及客户端自身的信息。

示例:

  • Accept:用于指定客户端接受哪些类型的信息。Accept:image/gif,表明客户端希望接受GIF图象格式的资源;Accept:text/html,表明客户端希望接受html文本。
  • Accept-Charset:用于指定客户端接受的字符集。Accept-Charset:iso-8859-1,gb2312.如果在请求消息中没有设置这个域,缺省是任何字符集都可以接受。
  • Accept-Encoding:类似于Accept,但是它是用于指定可接受的内容编码。Accept-Encoding:gzip.deflate.如果请求消息中没有设置这个域服务器假定客户端对各种内容编码都可以接受。
  • Accept-Language:类似于Accept,但是它是用于指定一种自然语言。eg:Accept-Language:zh-cn.如果请求消息中没有设置这个报头域,服务器假定客户端对各种语言都可以接受。
  • Authorization:主要用于证明客户端有权查看某个资源。当浏览器访问一个页面时,如果收到服务器的响应代码为401(未授权),可以发送一个包含Authorization请求报头域的请求,要求服务器对其进行验证。
  • Host(发送请求时,该报头域是必需的):主要用于指定被请求资源的Internet主机和端口号,它通常从HTTP URL中提取出来的,在浏览器中输入:http://www.seu.edu.cn/index.html, 浏览器发送的请求消息中,就会包含Host请求报头域,例:Host:www.seu.edu.cn,此处使用缺省端口号80,若指定了端口号,则变成:Host:www.seu.edu.cn:指定端口号。
  • User-Agent:User-Agent请求报头域允许客户端将它的操作系统、浏览器和其它属性告诉服务器。
1
2
3
4
5
6
7
8
9
10
GET /form.html HTTP/1.1 (CRLF)
Accept:image/gif,image/x-xbitmap,image/jpeg,application/x-shockwave-flash,application/vnd.ms-excel,application/vnd.ms-powerpoint,application/msword,*/* (CRLF)
Accept-Language:zh-cn (CRLF)
Accept-Encoding:gzip,deflate (CRLF)
If-Modified-Since:Wed,05 Jan 2016 11:21:25 GMT (CRLF)
If-None-Match:W/"80b1a4c018f3c41:8317" (CRLF)
User-Agent:Mozilla/8.0(compatible;MSIE10.0;Windows 7) (CRLF)
Host:www.seu.edu.cn (CRLF)
Connection:Keep-Alive (CRLF)
(CRLF)

5.3 响应报头

响应报头允许服务器传递不能放在状态行中的附加响应信息,以及关于服务器的信息和对Request-URI所标识的资源进行下一步访问的信息。

示例:

  • Location:用于重定向接受者到一个新的位置。Location响应报头域常用在更换域名的时候。
  • Server:包含了服务器用来处理请求的软件信息。与User-Agent请求报头域是相对应的,Server:Apache-Coyote/1.1。
  • WWW-Authenticate:必须被包含在401(未授权的)响应消息中,客户端收到401响应消息时候,并发送Authorization报头域请求服务器对其进行验证时,服务端响应报头就包含该报头域,WWW-Authenticate:Basic realm=”Basic Auth Test!”,可以看出服务器对请求资源采用的是基本验证机制。

5.4 实体报头

请求和响应消息都可以传送一个实体。一个实体由实体报头域和实体正文组成,但并不是说实体报头域和实体正文要在一起发送,可以只发送实体报头域。实体报头定义了关于实体正文(有无实体正文)和请求所标识的资源的元信息。

示例:

  • Content-Encoding:被用作媒体类型的修饰符,它的值指示了已经被应用到实体正文的附加内容的编码,因而要获得Content-Type报头域中所引用的媒体类型,必须采用相应的解码机制。Content-Encoding这样用于记录文档的压缩方法,Content-Encoding:gzip。
  • Content-Language:描述了资源所用的自然语言。没有设置该域则认为实体内容将提供给所有的语言阅读者,Content-Language:da。
  • Content-Length:用于指明实体正文的长度,以字节方式存储的十进制数字来表示。
  • Content-Type:用语指明发送给接收者的实体正文的媒体类型,Content-Type:text/html; charset=ISO-8859-1。
  • Last-Modified:用于指示资源的最后修改日期和时间。
  • Expires:给出响应过期的日期和时间。为了让代理服务器或浏览器在一段时间以后更新缓存中(再次访问曾访问过的页面时,直接从缓存中加载,缩短响应时间和降低服务器负载)的页面,可以使用Expires实体报头域指定页面过期的时间,Expires:Thu,15 Sep 2016 16:23:12 GMT。HTTP1.1的客户端和缓存必须将其他非法的日期格式(包括0)看作已经过期。为了让浏览器不要缓存页面,也可以利用Expires实体报头域,设置为0,jsp中程序如下:response.setDateHeader(“Expires”,”0”)。

6. 相关补充

HTTP1.0和HTTP1.1的区别?

6.1 可扩展性

可扩展性的一个重要原则:如果HTTP的某个实现接收到了自身未定义的头域,将自动忽略它。

  • 在消息中增加版本号,用于兼容性判断。注意,版本号只能用来判断逐段(hop-by-hop)的兼容性,而无法判断端到端(end-to-end)的兼容性。例如,一台HTTP/1.1的源服务器从使用HTTP/1.1的Proxy那儿接收到一条转发的消息,实际上源服务器并不知道终端客户使用的是HTTP/1.0还是HTTP/1.1。因此,HTTP/1.1定义Via头域,用来记录消息转发的路径,它记录了整个路径上所有发送方使用的版本号。
  • HTTP/1.1增加了OPTIONS方法,它允许客户端获取一个服务器支持的方法列表。
  • 为了与未来的协议规范兼容,HTTP/1.1在请求消息中包含了Upgrade头域,通过该头域,客户端可以让服务器知道它能够支持的其它备用通信协议,服务器可以据此进行协议切换,使用备用协议与客户端进行通信。

6.2 缓存

HTTP/1.0中,使用Expire头域来判断资源的fresh或stale,并使用条件请求(conditional request)来判断资源是否仍有效。例如,cache服务器通过If-Modified-Since头域向服务器验证资源的Last-Modefied头域是否有更新,源服务器可能返回304(Not Modified),则表明该对象仍有效;也可能返回200(OK)替换请求的Cache对象。此外,HTTP/1.0中还定义了Pragma:no-cache头域,客户端使用该头域说明请求资源不能从cache中获取,而必须回源获取。

  • HTTP/1.1在1.0的基础上加入了一些cache的新特性,当缓存对象的Age超过Expire时变为stale对象,cache不需要直接抛弃stale对象,而是与源服务器进行重新激活(revalidation)。
  • HTTP/1.0中,If-Modified-Since头域使用的是绝对时间戳,精确到秒,但使用绝对时间会带来不同机器上的时钟同步问题。而HTTP/1.1中引入了一个ETag头域用于重激活机制,它的值entity tag可以用来唯一的描述一个资源。请求消息中可以使用If-None-Match头域来匹配资源的entitytag是否有变化。
  • 为了使caching机制更加灵活,HTTP/1.1增加了Cache-Control头域(请求消息和响应消息都可使用),它支持一个可扩展的指令子集:例如max-age指令支持相对时间戳;private和no-store指令禁止对象被缓存;no-transform阻止Proxy进行任何改变响应的行为。
  • Cache使用关键字索引在磁盘中缓存的对象,在HTTP/1.0中使用资源的URL作为关键字。但可能存在不同的资源基于同一个URL的情况,要区别它们还需要客户端提供更多的信息,如Accept-Language和Accept-Charset头域。为了支持这种内容协商机制(content negotiation mechanism),HTTP/1.1在响应消息中引入了Vary头域,该头域列出了请求消息中需要包含哪些头域用于内容协商。

6.3 带宽优化

HTTP/1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了。例如,客户端只需要显示一个文档的部分内容,又比如下载大文件时需要支持断点续传功能,而不是在发生断连后不得不重新下载完整的包。

  • HTTP/1.1中在请求消息中引入了range头域,它允许只请求资源的某个部分。在响应消息中Content-Range头域声明了返回的这部分对象的偏移值和长度。如果服务器相应地返回了对象所请求范围的内容,则响应码为206(Partial Content),它可以防止Cache将响应误以为是完整的一个对象。
    另外一种情况是请求消息中如果包含比较大的实体内容,但不确定服务器是否能够接收该请求(如是否有权限),此时若贸然发出带实体的请求,如果被拒绝也会浪费带宽。
  • HTTP/1.1加入了一个新的状态码100(Continue)。客户端事先发送一个只带头域的请求,如果服务器因为权限拒绝了请求,就回送响应码401(Unauthorized);如果服务器接收此请求就回送响应码100,客户端就可以继续发送带实体的完整请求了。注意,HTTP/1.0的客户端不支持100响应码。但可以让客户端在请求消息中加入Expect头域,并将它的值设置为100-continue。

节省带宽资源的一个非常有效的做法就是压缩要传送的数据。Content-Encoding是对消息进行端到端(end-to-end)的编码,它可能是资源在服务器上保存的固有格式(如jpeg图片格式);在请求消息中加入Accept-Encoding头域,它可以告诉服务器客户端能够解码的编码方式。而Transfer-Encoding是逐段式(hop-by-hop)的编码,如Chunked编码。在请求消息中加入TE头域用来告诉服务器能够接收的transfer-coding方式。

6.4 长连接

HTTP 1.0规定浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器完成请求处理后立即断开TCP连接,服务器不跟踪每个客户也不记录过去的请求。此外,由于大多数网页的流量都比较小,一次TCP连接很少能通过slow-start区,不利于提高带宽利用率。

  • HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟。例如:一个包含有许多图像的网页文件的多个请求和应答可以在一个连接中传输,但每个单独的网页文件的请求和应答仍然需要使用各自的连接。
  • HTTP 1.1还允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能够区分出每次请求的响应内容,这样也显著地减少了整个下载过程所需要的时间。

在HTTP/1.0中,要建立长连接,可以在请求消息中包含Connection: Keep-Alive头域,如果服务器愿意维持这条连接,在响应消息中也会包含一个Connection: Keep-Alive的头域。同时,可以加入一些指令描述该长连接的属性,如max,timeout等。
事实上,Connection头域可以携带三种不同类型的符号:

  • 一个包含若干个头域名的列表,声明仅限于一次hop连接的头域信息;
  • 任意值,本次连接的非标准选项,如Keep-Alive等;
  • close值,表示消息传送完成之后关闭长连接;

客户端和源服务器之间的消息传递可能要经过很多中间节点的转发,这是一种逐跳传递(hop-by-hop)。

  • HTTP/1.1相应地引入了hop-by-hop头域,这种头域仅作用于一次hop,而非整个传递路径。每一个中间节点(如Proxy,Gateway)接收到的消息中如果包含Connection头域,会查找Connection头域中的一个头域名列表,并在将消息转发给下一个节点之前先删除消息中这些头域。通常,HTTP/1.0的Proxy不支持Connection头域,为了不让它们转发可能误导接收者的头域,协议规定所有出现在Connection头域中的头域名都将被忽略。

6.5 消息传递

HTTP消息中可以包含任意长度的实体,通常它们使用Content-Length来给出消息结束标志。但是,对于很多动态产生的响应,只能通过缓冲完整的消息来判断消息的大小,但这样做会加大延迟。如果不使用长连接,还可以通过连接关闭的信号来判定一个消息的结束。

  • HTTP/1.1中引入了Chunkedtransfer-coding来解决上面这个问题,发送方将消息分割成若干个任意大小的数据块,每个数据块在发送时都会附上块的长度,最后用一个零长度的块作为消息结束的标志。这种方法允许发送方只缓冲消息的一个片段,避免缓冲整个消息带来的过载。
  • 在HTTP/1.0中,有一个Content-MD5的头域,要计算这个头域需要发送方缓冲完整个消息后才能进行。而HTTP/1.1中,采用chunked分块传递的消息在最后一个块(零长度)结束之后会再传递一个拖尾(trailer),它包含一个或多个头域,这些头域是发送方在传递完所有块之后再计算出值的。发送方会在消息中包含一个Trailer头域告诉接收方这个拖尾的存在。
    状态

6.6 Host头域

在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。

  • HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。此外,服务器应该接受以绝对路径标记的资源请求。

6.7 错误提示

  • HTTP/1.0中只定义了16个状态响应码,对错误或警告的提示不够具体。HTTP/1.1引入了一个Warning头域,增加对错误或警告信息的描述。
  • 此外,在HTTP/1.1中新增了24个状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。

6.8 内容协商

为了满足互联网使用不同母语和字符集的用户,一些网络资源有不同的语言版本(如中文版、英文版)。HTTP/1.0定义了内容协商(contentnegotiation)的概念,也就是说客户端可以告诉服务器自己可以接收以何种语言(或字符集)表示的资源。例如如果服务器不能明确客户端需要何种类型的资源,会返回300(Multiple Choices),并包含一个列表,用来声明该资源的不同可用版本,然后客户端在请求消息中包含Accept-Language和Accept-Charset头域指定需要的版本。
就像有些人会说几门外语,但每种外语的流利程度并不相同。类似地,网络资源也可以有不同的表达形式,比如有母语版和各种翻译版本。HTTP引入了一个品质因子(quality values)的概念来表示不同版本的可用性,它的取值从0.0到1.0。例如一个母语是英语的人也能讲法语、甚至还学了点丹麦语,那么他的浏览器可用作如下配置:Accept-Language: en, fr;q=0.5, da;q=0.1。这时,服务器会优先选取品质因子高的值对应的资源版本作为响应。