1 基础概念

HTTP(超文本传输协议)是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式,HTTP1.1版本中给出一种持续连接的机制,绝大多数的Web开发,都是构建在HTTP协议之上的Web应用。

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

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

1.1 URI

URI统一资源标识符(Unicform Resource Identifier):唯一标识并定位信息资源.它有两个子集,一个是URL(Unicform Resource Locator),另一个是URN(Unicform Resource Name)

1.1.1 URL

URL (URL是一种特殊类型的URI,包含了用于查找某个资源的足够的信息)的格式如下:

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

eg:

  1. 输入:www.guet.edu.cn 浏览器自动转换成:http://www.guet.edu.cn/
  2. http:192.168.0.116:8080/index.jsp

1.1.2 URN

URN:URL的一种更新形式,统一资源名称(URN, Uniform Resource Name)不依赖于位置,并且有可能减少失效连接的个数。但是其流行还需假以时日,因为它需要更精密软件的支持。

1.2 层次关系

HTTP协议通常承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候,就成了我们常说的HTTPS。如下图所示:

默认HTTP的端口号为80,HTTPS的端口号为443。

1.3 HTTP的请求响应模型

HTTP协议永远都是客户端发起请求,服务器回送响应。

这样就限制了使用HTTP协议,无法实现在客户端没有发起请求的时候,服务器将消息推送给客户端

HTTP协议是一个无状态的协议,同一个客户端的这次请求和上次请求是没有对应关系。

1.4 工作流程

一次HTTP操作称为一个事务,其工作过程可分为四步:

  1. 首先客户机与服务器需要建立连接。只要单击某个超级链接,HTTP的工作开始。
  2. 建立连接后,客户机发送一个请求给服务器,请求方式的格式为:统一资源标识符(URL)、协议版本号,后边是MIME信息包括请求修饰符、客户机信息和可能的内容。
  3. 服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是MIME信息包括服务器信息、实体信息和可能的内容。
  4. 客户端接收服务器所返回的信息通过浏览器显示在用户的显示屏上,然后客户机与服务器断开连接。

如果在以上过程中的某一步出现错误,那么产生错误的信息将返回到客户端,有显示屏输出。对于用户来说,这些过程是由HTTP自己完成的,用户只要用鼠标点击,等待信息显示就可以了。

1.5 查看HTTP

我们可以在chrome的审查元素里查看network,也可以用firefox的LiveHTTP插件,下面是访问www.baidu.com返回的http:

GET / HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36
DNT: 1
Accept-Encoding: gzip,deflate,sdch
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4,ja;q=0.2

HTTP/1.1 200 OK
Date: Sun, 16 Nov 2014 06:43:47 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: Keep-Alive
Vary: Accept-Encoding
Set-Cookie: BAIDUID=53D3052AEE1A2972D5AED1E505323E95
Cache-Control: private
Cxy_all: baidu+8e65b23e6d5bd3877ec23fa1c478e07c
Expires: Sun, 16 Nov 2014 06:42:56 GMT
X-Powered-By: HPHP
Server: BWS/1.1
BDPAGETYPE: 1
BDQID: 0xfa409b4000452dee
BDUSERID: 0
Content-Encoding: gzip

从上面可以看到,HTTP协议的请求消息和响应消息有固定的格式

-------------------------请求头格式------------------------------------------------------------------
HTTP请求行 
(请求)头 
空行 
可选的消息体 
---------------------------响应头格式----------------------------------------------------------------
HTTP状态行 
(应答)头 
空行 
可选的消息体

2 HTTP报文

2.1 HTTP请求报文(request message)

HTTP协议的请求主要由一下几部分组成:请求行,请求头,请求体(post)

请求行\r\n
请求头1\r\n
请求头1\r\n
...
\r\n
请求体(Post方式)\r\n

2.1.1 请求行

请求行主要由三部分组成,请求方法,请求路径,请求协议.例如上面的:

GET / HTTP/1.1

常用的HTTP方法:

方法 描述 是否包含主体
GET 从服务器获取一份文档 ×
HEAD 只从服务器获取文档首部 ×
POST 向服务器发送需要处理的数据
PUT 将请求的主体部分存储在服务器上
TRACE 对可能经过代理服务器传送到服务器上去的报文进行追踪 ×
OPTIONS 决定可以在服务器上执行那些方法 ×
DELETE 从服务器删除一份文档 ×

还有一种CONNECT,已文档化但当前未实现的一个方法,预留做隧道处理

当然我们最常用的也就是get和post方法,get方法的请求方式比较简单,所有请求的参数都显示追加在请求的url后面,而且请求长度有限制,post方式的请求参数都追加在请求体当中,消息长度没有限制而且以隐式的方式进行发送,安全性相对较高(这个安全性对于现在的网络技术也没有什么可安全的了,^_^)。

请求路径:请求路径可以是相对或者绝对的方式,绝对路径不去阐述,相对路径是相对于当前TCP连接的主机的路径(HTTP/1.0方式),在HTTP/1.1方式当中相对于的是请求头当中的host域,HTTP/1.1的新特性会在以后的方式当中进行阐述

请求协议:目前常用的支持HTTP/1.0和HTTP/1.1方式,HTTP/1.1和HTTP/1.0之间存在不少差异性,

2.1.2 请求头

比如上面的例子中:

Host: www.baidu.com
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36
DNT: 1
Accept-Encoding: gzip,deflate,sdch
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4,ja;q=0.2

请求头都是以key:value形式进行保存的,里面记录了客户端的一些基本信息,常用的请求头如下所示.

  1. Host:客户端IP和端口

    Host: www.baidu.com
    
  2. User-Agent:浏览器信息

    User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36
    
  3. Accept:客户端能接收的数据类型

    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    
  4. Accept-Encoding:浏览器能够进行解码的数据编码方式,比如gzip。Servlet能够向支持gzip的浏览器返回经gzip编码的HTML页面。许多情形下这可以减少5到10倍的下载时间

    Accept-Encoding: gzip,deflate,sdch
    
  5. Accept-charset:客户端字符编码集

  6. Accept-Language:浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到。

    Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4,ja;q=0.2
    
  7. Authorization:授权信息,通常出现在对服务器发送的WWW-Authenticate头的应答中。

  8. Connection:表示是否需要持久连接。如果Servlet看到这里的值为“Keep-Alive”,或者看到请求使用的是HTTP 1.1(HTTP 1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如Applet,图片),显著地减少下载所需要的时间。要实现这一点,Servlet需要在应答中发送一个Content-Length头,最简单的实现方法是:先把内容写入ByteArrayOutputStream,然后在正式写出内容之前计算它的大小。

    Connection: keep-alive
    
  9. Content-Length:表示请求消息正文的长度。

  10. Cookie:这是最重要的请求头信息之一。

  11. From:请求发送者的email地址,由一些特殊的Web客户程序使用,浏览器不会用到它。

  12. If-Modified-Since:只有当所请求的内容在指定的日期之后又经过修改才返回它,否则返回304“Not Modified”应答。

  13. Pragma:指定“no-cache”值表示服务器必须返回一个刷新后的文档,即使它是代理服务器而且已经有了页面的本地拷贝。

  14. Referer:包含一个URL,用户从该URL代表的页面出发访问当前请求的页面。

    Referer: http://www.baidu.com/
    
  15. UA-Pixels,UA-Color,UA-OS,UA-CPU:由某些版本的IE浏览器所发送的非标准的请求头,表示屏幕大小、颜色深度、操作系统和CPU类型.

2.1.3 请求体

请求体(又叫请求正文)是post请求方式当中的请求参数,get方式则无请求体,以key=value形式进行存储,多个请求参数之间用&连接,如果请求当中有请求提,那么在请求头当中的Content-Length属性中记录的是该请求体的长度。

POST hysj.jsp HTTP/1.1
Host: search.cnipr.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; zh-CN; rv:1.9.1.13) Gecko/20100914 Firefox/3.5.13 ( .NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://search.cnipr.com/cnipr/zljs/hyjs-biaodan-y.jsp
Content-Length: 405
username=guest&extension=&issearch=on&searchword=pd%3D%2820100901%29&presearchword=&sortfield=RELEVANCE&sRecordNumber=&searchType=0&searchFrom=0&channelid=14%2C15%2C16&searchChannel=14%2C15%2C16&strdb=14&strdb=15&strdb=16&cizi=2&sortcolumn=RELEVANCE&R1=-&txtA=&txtB=&txtC=&txtD=20100901&txtE=&txtF=&txtG=&txtH=&txtI=&txtJ=&txtK=&txtL=&txtM=&txtN=&txtP=&txtQ=&txtR=&txtSearchWord=&Submit=%BC%EC%A1%A1%CB%F7

2.2 HTTP响应报文(response message)

HTTP响应信息(服务器信息)

  1. 状态行:HTTP版本 服务器状态(比如:404找不到...) 描述信息
  2. 响应头
  content-text:服务器发送信息的类型
  date:发送时间
  server:服务器类型
  1. 消息体:服务器发送给客户端的页面内容

HTTP响应的格式类似于请求的格式,主要由响应行,响应头,响应体组成,其格式如下所示

响应行\r\n
响应头\r\n
响应头\r\n
...

响应体

2.2.1 响应行

HTTP/1.1 200 OK

标识服务器端对客户端请求的处理结果,主要由响应状态信息,响应状态码,服务器协议.

响应状态信息:HTTP协议

状态代码分类:

整体范围 已定义范围 分类
100 ~ 199 100 ~ 101 信息提示
200 ~ 299 200 ~ 206 成功
300 ~ 399 300 ~ 305 重定向
400 ~ 499 400 ~ 415 客户端错误
500 ~ 599 500 ~ 505 服务器错误

响应状态码:

  1. 消息(1字头):这一类型的状态码,代表请求已被接受,需要继续处理。这类响应是临时响应,只包含状态行和某些可选的响应头信息,并以空行结束。由于 HTTP/1.0 协议中没有定义任何 1xx 状态码,所以除非在某些试验条件下,服务器禁止向此类客户端发送 1xx 响应。

    100 继续
    101 分组交换协
    
  2. 成功(2字头):这一类型的状态码,代表请求已成功被服务器接收、理解、并接受。

    200 OK
    201 被创建
    202 被采纳
    203 非授权信息
    204 无内容
    205 重置内容
    206 部分内容
    
  3. 重定向(3字头):这类状态码代表需要客户端采取进一步的操作才能完成请求。通常,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的 Location 域中指明。

    300 多选项
    301 永久地传送
    302 找到
    303 参见其他
    304 未改动
    305 使用代理
    307 暂时重定向
    
  4. 请求错误(4字头):这类的状态码代表了客户端看起来可能发生了错误,妨碍了服务器的处理。除非响应的是一个 HEAD 请求,否则服务器就应该返回一个解释当前错误状况的实体,以及这是临时的还是永久性的状况。这些状态码适用于任何请求方法。浏览器应当向用户显示任何包含在此类错误响应中的实体内容。

    400 错误请求
    401 未授权
    402 要求付费
    403 禁止
    404 未找到
    405 不允许的方法
    406 不被采纳
    407 要求代理授权
    408 请求超时
    409 冲突
    410 过期的
    411 要求的长度
    412 前提不成立
    413 请求实例太大
    414 请求URI太大
    415 不支持的媒体类型
    416 无法满足的请求范围
    417 失败的预期
    
  5. 服务器错误(5字头):这类状态码代表了服务器在处理请求的过程中有错误或者异常状态发生,也有可能是服务器意识到以当前的软硬件资源无法完成对请求的处理。除非这是一个HEAD 请求,否则服务器应当包含一个解释当前错误状态以及这个状况是临时的还是永久的解释信息实体。浏览器应当向用户展示任何在当前响应中被包含的实体。

    500 内部服务器错误
    501 未被使用
    502 网关错误
    503 不可用的服务
    504 网关超时
    505 HTTP版本未被支持
    

常见的状态码:

200 OK      //客户端请求成功
400 Bad Request  //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用 
403 Forbidden  //服务器收到请求,但是拒绝提供服务
404 Not Found  //请求资源不存在,eg:输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable  //服务器当前不能处理客户端的请求,一段时间后可能恢复正常

2.2.2 响应头

类似于请求头的key:value形式,常用响应头如下所示:

  1. Location:这个头通常配合302状态码使用,它用于告诉浏览器你去找谁。
  2. Server:告诉浏览器,服务器的类型
  3. Content-Encoding: 服务器通过这个头,告诉浏览器,回送的数据采用的压缩格式。
  4. Content-Length: 80
  5. Content-Language: zh-cn
  6. Content-Type:这个头用于告诉浏览器,回送数据的类型
  7. Last-Modified:这个头用于告诉浏览器,数据的最后修改时间
  8. Refresh: :这个头用于控制浏览器定时刷新
  9. Content-Disposition: 用于通知浏览器,以下载方式打开回送的数据
  10. Transfer-Encoding: 用于通知浏览器,数据是以分块形式回送的
  11. ETag: 缓存相头的头
  12. Expires: 用于说明网页的失效时间,如果该值为一个<0的值,则服务器是通知浏览器不要缓存
  13. Cache-Control: no-cache 通知浏览器不要缓存
  14. Pragma: no-cache

上面只是简单介绍了下,如需详细还需要查阅手册.

HTTP权威指南

3 wireshark抓包查看HTTP过程

下面是打开www.baidu.com所有的包:

No.     Time           Source                Destination           Protocol Length Info
    355 4.170229000    222.26.7.125          119.75.217.56         TCP      74     50536 > http [SYN] Seq=0 Win=29200 Len=0 MSS=1460 SACK_PERM=1 TSval=7178795 TSecr=0 WS=128
    356 4.183233000    119.75.217.56         222.26.7.125          TCP      74     http > 50536 [SYN, ACK] Seq=0 Ack=1 Win=29200 Len=0 MSS=1440 SACK_PERM=1 WS=128
    357 4.183284000    222.26.7.125          119.75.217.56         TCP      54     50536 > http [ACK] Seq=1 Ack=1 Win=29312 Len=0
    358 4.183343000    222.26.7.125          119.75.217.56         HTTP     131    GET / HTTP/1.1 
    359 4.196633000    119.75.217.56         222.26.7.125          TCP      60     http > 50536 [ACK] Seq=1 Ack=78 Win=24704 Len=0
    360 4.199425000    119.75.217.56         222.26.7.125          TCP      943    [TCP segment of a reassembled PDU]
    361 4.199454000    222.26.7.125          119.75.217.56         TCP      54     50536 > http [ACK] Seq=78 Ack=890 Win=32128 Len=0
    362 4.199635000    119.75.217.56         222.26.7.125          TCP      1494   [TCP segment of a reassembled PDU]
    363 4.199652000    222.26.7.125          119.75.217.56         TCP      54     50536 > http [ACK] Seq=78 Ack=2330 Win=35072 Len=0
    364 4.199766000    119.75.217.56         222.26.7.125          TCP      1494   [TCP segment of a reassembled PDU]

...

    475 4.217795000    222.26.7.125          119.75.217.56         TCP      54     50536 > http [ACK] Seq=78 Ack=82970 Win=184192 Len=0
    476 4.217832000    119.75.217.56         222.26.7.125          HTTP     556    HTTP/1.1 200 OK  (text/html)
    477 4.217835000    222.26.7.125          119.75.217.56         TCP      54     50536 > http [ACK] Seq=78 Ack=83472 Win=183808 Len=0
    478 4.218827000    222.26.7.125          119.75.217.56         TCP      54     50536 > http [FIN, ACK] Seq=78 Ack=83472 Win=185856 Len=0
    479 4.232403000    119.75.217.56         222.26.7.125          TCP      60     http > 50536 [ACK] Seq=83472 Ack=79 Win=24704 Len=0
    480 4.232442000    119.75.217.56         222.26.7.125          TCP      60     http > 50536 [FIN, ACK] Seq=83472 Ack=79 Win=24704 Len=0
    481 4.232468000    222.26.7.125          119.75.217.56         TCP      54     50536 > http [ACK] Seq=79 Ack=83473 Win=185856 Len=0

可以清楚的看到HTTP的详细过程:

  1. 355,356,357是三次握手的过程
  2. 然后浏览器发送HTTP请求,其实这次请求是夹在第三次握手的包中的,可以看到HTTP包的详细信息

    Transmission Control Protocol, Src Port: 50536 (50536), Dst Port: http (80), Seq: 1, Ack: 1, Len: 77
    

    它的seq=1,所以它是来自上一个TCP包.因为HTTP是由TCP包包装成的,所以这里显示的HTTP包其实是前面的TCP包的解包.

  3. 接下来是一连串由服务器发来的TCP包和浏览器确认TCP包.

  4. 直到476浏览器请求的所有TCP包都被接受,这时TCP按照序号把所有TCP包拆解并组成HTTP包.

  5. 478~481最后4个为4次挥手.

参考资料