计算机网络协议赏析-HTTP

参考资料:
HTTP协议详解
计算机网络协议赏析-HTTP
简明HTTP协议
HTTP 状态代码解释

【最熟悉的陌生人】

和TCP/UDP协议比起来,HTTP协议或许更为大家所熟知,因为大家处处都可以看到http://xxx.com的字样。
但是,真正了解HTTP协议的同学,或许只是少数,还有很多人甚至不知道“404”的含义。
而本文,正是让大家来更深入的了解下这位最熟悉的陌生人。

【HTTP在江湖中的地位】

众所周知,Internet四层网络模型(也叫TCP/IP四层模型)包括数据链路层、网络层、传输层和应用层,
网络层最著名的协议是IP协议,传输层最著名的协议是TCP协议和UDP协议,而应用层的协议众多,诸如FTP协议、TELNET协议、TFTP协议、POP协议、SMTP协议、DNS协议、SNMP协议,当然还包括了本文的主角HTTP协议。
如果说TCP/UDP/IP协议算作幕后的英雄,那毫不夸张的说,HTTP协议则是台前最大腕的明星。

【HTTP大概是怎样工作的】

HTTP,是符合Client/Server模型的,总是Client端来发起请求。整个过程,可以简单分为四步:
(1)客户端发起请求,与服务器端完成“TCP三次握手”(TCP三次握手非文本重点知识)
(2)客户端向服务器端发出“HTTP请求报文”
(3)服务器端在完成内部处理后,向客户端发出“HTTP响应报文”
(4)客户端与服务器端完成“TCP四次分手”(TCP四次分手非文本重点知识)
而HTTP协议本身是一种无状态的协议,也就是说每一个HTTP报文不依赖于其前面的报文状态。

【HTTP的URL如何表示】

之所以要先讲一下URL,是因为这个知识点在下文中会频繁用到。
HTTP协议中的URL主要是用于定位服务器端资源的位置。我们来看下它的语法定义:
http://host[:port][path]
其中:
http:// 表示我们要使用HTTP协议;
host 表示一个可用的域名或IP地址;
port 为可选,表示要请求的端口号,缺省情况下为80
path 为可选,表示要请求的资源所在的路径(也叫URI),缺省情况下为/

 
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
      
schema://host[:port#]/path/.../[?query-string][#anchor]
scheme:指定低层使用的协议(例如:http, https, ftp)
host:HTTP服务器的IP地址或者域名
port#:HTTP服务器的默认端口是80,这种情况下端口号可以省略。如果使用了别的端口,必须指明,例如 http://www.cnblogs.com:8080/
path :访问资源的路径
query-string:发送给http服务器的数据
anchor-:锚
URL 的一个例子
http://www.mywebsite.com/sj/test/test.aspx?name=sviergn&x=true#stuff
Schema: http
host: www.mywebsite.com
path: /sj/test/test.aspx
Query String: name=sviergn&x=true
Anchor: stuff

【HTTP请求长什么样儿】

我们先来看一个典型的HTTP请求报文长什么样子:
(我们用//注释嵌到请求里,让大家更好的理解每一行语句的含义)

第一行叫做请求行(request),其他的各行都叫做头部行(header)
请求行包括三个字段:方法字段、URI字段、HTTP版本字段
这个例子的请求行,是要做这样一件事:用HTTP协议1.1版本,使用GET方法,
向服务端申请pathtopage.html资源
GET pathtopage.html HTTP1.1

下面都属于头部行 
Host用来指定要请求的服务器端主机为roclinux.cn
Host:roclinux.cn
Connection:close是要告诉服务器端,我客户端不想使用持久连接,
请服务器端在完成这次请求响应后关闭此连接。虽然这个请求报文中
使用了支持持久连接的HTTP1.1版本,但客户端仍然不想使用持久连接
Connection:close
User-agent域则是用来指定当前这个请求报文是由谁产生的,通常来
说,一般这里设置的是用户所使用的浏览器类型。不要小看这个域,一
些用心的站长,会通过这个域来识别客户,并给不同的客户展示资源的
不同版本呢!
User-agent:Mozilla4.0
Accept-language域,则是客户端再跟服务器端说“兄弟,如果你那里有
我申请的资源的中文版本,那就把中文版本给我;如果没有中文版本,那
就把你的默认语言版本给我就好了。”
Accept-language:zh-cn
看这里,看这里!或许谁也没有注意到这里,这里有一个空行,而且是必
须有这个空行。这是HTTP协议的硬性规定,不要忘记哦

下面,用我精心画的一张图,来说明下请求报文的协议格式:


HTTP协议-请求报文格式
从上面这个图,应该可以很清晰的看出请求报文的具体格式啦。

【HTTP请求报文中有哪些方法】
HTTP请求方法有很多,我们先走马观花的看看:
GET方法:请求某资源
POST方法:请求某资源的同时附上一些数据
HEAD方法:请求某资源对应的响应报文头
PUT方法:上传一个资源
DELETE方法:删除一个资源
TRACE方法:让服务器回送请求报文,用于调试和排障
OPTIONS:请求服务器性能信息
CONNECT:预留给代理服务器所用


【怎么响应HTTP的请求】

在了解完请求报文的格式之后,你是不是想知道HTTP协议是如何响应请求报文的呢?我们来看一个典型的响应报文:

一个响应报文,一般包括三部分,即状态行、头部行、附属体
第一行是状态行,包括三个字段:版本字段、状态码字段、原因短语字段
本例中,HTTP协议的响应报文想表达的意思是服务器使用的是HTTP协议1.1版本,
而且找到了客户端所要的资源,且会将响应报文发给客户端,整个过程都很正常
HTTP1.1 200 0K
服务器端不会保持住这个连接,而是在回复完这个响应报文之后会断开这个连接
Connectlon:close
这里记录了这个响应报文被发送出去的时间点
Date: Thu, 13 Oct 2005 03:17:33 GMT
Server域表明这个响应报文是有类Unix操作系统上的Apache服务器发出的,且
Apache的版本是2.0.54
Server: Apache2.0.54 (Unix)
用于记录本响应报文中所存的数据的最后修改时间
Last—Modified:Mon,22 Jun 1998 09;23;24 GMT
指出数据部分的字节数,即单位Byte
Content—Length:682l
指出所包含的数据是HTML文本内容
Content—Type:texthtml
看这里,还得看这里,和请求报文类似,这里也有一个空行,不能省哦
这里是实际的响应数据
(data data data data …………)

下面,我们同样来看看响应报文的协议格式:

HTTP协议-响应报文格式


【说说HTTP的状态码】

说到HTTP响应报文,就不得不提到HTTP状态码,及原因短语。相信大家看完这一小节后,就会很清楚404代表着什么了。
状态码总共只有三位,第一位表示状态类别,共分五种,我们来依次看一下:
1xx:是进度通知类状态,意思就是说“请求我已经收到了,或你的请求我正在处理”;
2xx:表示“你的请求我已经成功处理了”;
3xx:即重定向,也就是服务器告诉客户端“你要的资源搬家了,你到某某地方再去找他吧”;
4xx:客户端发来的响应报文里有些错误,比如语法错误或请求的资源不存在等;
5xx:服务器端有些问题,已经无法处理完成你的请求了。
其实常用的状态码并不多,我们把常见的列举在此:
200 OK:客户端请求成功了,客户端要的东西就在响应报文里了;
301 Moved Permanently:客户端啊,你要请求的资源已经永久的搬家了,我把他的新地址放到了Location头部域中了;
302 Moved Temporarily:客户端啊,你要请求的资源临时有事去别的地方了,我把他的位置放到了Location头部域中了,你可以先去那里找他,不过他应该是会回到他自己的家的;
304 Not Modified:客户端啊,你要请求的资源自从上次你请求之后,就再也没有改动过,我想你是应该早就有这个资源了,所以在响应报文的数据部分我也没有再放这个资源。
400 Bad Request:客户端发来的请求报文里有语法错误,服务器端实在看不懂了;
401 Unauthorized:客户端发来的请求不是合法来源的请求,也就是这个客户端是没有被授权的;
403 Forbidden:服务器端顺利收到了客户端的请求,但是因为某些理由,服务器端拒绝为他提供服务;
404 Not Found:客户端要请求的资源不存在,八成是资源地址写错了;
500 Internal Server Error:很遗憾,服务器不能给你提供服务了,服务器内部出现了不可预知的问题了;
502 Bad Gateway:客户端你好,我是请求报文的代理服务器,持有资源的那个服务器在给我发送资源时出问题了;
503 Server Unavailable:服务器现在可能是太忙了,暂时不能给你这个客户端提供服务了,或许稍后会恢复。

【常见的状态码】
200 OK最常见的就是成功响应状态码200了, 这表明该请求被成功地完成,所请求的资源发送回客户端.如下图, 打开博客园首页

302 Found.重定向,新的URL会在response 中的Location中返回,浏览器将会自动使用新的URL发出新的Request。例如在IE中输入, http://www.google.com. HTTP服务器会返回302, IE取到Response中Location header的新URL, 又重新发送了一个Request.

304 Not Modified。代表上次的文档已经被缓存了, 还可以继续使用,例如打开博客园首页, 发现很多Response 的status code 都是304

400 Bad Request 客户端请求与语法错误,不能被服务器所理解
403 Forbidden 服务器收到请求,但是拒绝提供服务
  404 Not Found请求资源不存在(输错了URL)。比如在IE中输入一个错误的URL, http://www.cnblogs.com/tesdf.aspx

【HTTP Request header】

使用Fiddler 能很方便的查看Reques header, 点击Inspectors tab ->Request tab-> headers 如下图所示.

Cache 头域
If-Modified-Since。作用: 把浏览器端缓存页面的最后修改时间发送到服务器去,服务器会把这个时间与服务器上实际文件的最后修改时间进行对比。如果时间一致,那么返回304,客户端就直接使用本地缓存文件。如果时间不一致,就会返回200和新的文件内容。客户端接到之后,会丢弃旧文件,把新文件缓存起来,并显示在浏览器中.
  例如:If-Modified-Since: Thu, 09 Feb 2012 09:07:57 GMT
实例如下图

If-None-Match.作用: If-None-Match和ETag一起工作,工作原理是在HTTP Response中添加ETag信息。 当用户再次请求该资源时,将在HTTP Request 中加入If-None-Match信息(ETag的值)。如果服务器验证资源的ETag没有改变(该资源没有更新),将返回一个304状态告诉客户端使用本地缓存文件。否则将返回200状态和新的资源和Etag. 使用这样的机制将提高网站的性能.例如: If-None-Match: “03f2b33c0bfcc1:0”.实例如下图

Pragma。作用: 防止页面被缓存, 在HTTP/1.1版本中,它和Cache-Control:no-cache作用一模一样Pargma只有一个用法, 例如: Pragma: no-cache注意: 在HTTP/1.0版本中,只实现了Pragema:no-cache, 没有实现Cache-Control
  Cache-Control。作用: 这个是非常重要的规则。 这个用来指定Response-Request遵循的缓存机制。各个指令含义如下:
Cache-Control:Public 可以被任何缓存所缓存()
Cache-Control:Private 内容只缓存到私有缓存中
Cache-Control:no-cache 所有内容都不会被缓存

Client 头域
Accept。作用: 浏览器端可以接受的媒体类型,例如: Accept: text/html 代表浏览器可以接受服务器回发的类型为 text/html ,也就是我们常说的html文档,如果服务器无法返回text/html类型的数据,服务器应该返回一个406错误(non acceptable)。通配符 代表任意类型。例如 Accept: / 代表浏览器可以处理所有类型,(一般浏览器发给服务器都是发这个)

Accept-Encoding:作用: 浏览器申明自己接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法(gzip,deflate),(注意:这不是只字符编码);例如: Accept-Encoding: gzip, deflate
Accept-Language。作用: 浏览器申明自己接收的语言。 语言跟字符集的区别:中文是语言,中文有多种字符集,比如big5,gb2312,gbk等等;例如: Accept-Language: en-us
User-Agent。作用:告诉HTTP服务器, 客户端使用的操作系统和浏览器的名称和版本.例如: User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; CIBA; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; InfoPath.2; .NET4.0E)
Accept-Charset作用:浏览器申明自己接收的字符集,这就是本文前面介绍的各种字符集和字符编码,如gb2312,utf-8(通常我们说Charset包括了相应的字符编码方案)。
Cookie/Login 头域
Cookie:作用: 最重要的header, 将cookie的值发送给HTTP 服务器
Entity头域
Content-Length作用:发送给HTTP服务器数据的长度。例如: Content-Length: 38
Content-Type作用:例如:Content-Type: application/x-www-form-urlencoded
Miscellaneous 头域
Referer:作用: 提供了Request的上下文信息的服务器,告诉服务器我是从哪个链接过来的,比如从我主页上链接到一个朋友那里,他的服务器就能够从HTTP Referer中统计出每天有多少用户点击我主页上的链接访问他的网站。
例如: Referer:http://translate.google.cn/?hl=zh-cn&tab=wT
*Transport 头域

Connection例如:Connection: keep-alive 当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。例如: Connection: close 代表一个Request完成后,客户端和服务器之间用于传输HTTP数据的TCP连接会关闭, 当客户端再次发送Request,需要重新建立TCP连接。
Host(发送请求时,该报头域是必需的)作用: 请求报头域主要用于指定被请求资源的Internet主机和端口号,它通常从HTTP URL中提取出来的。例如: 我们在浏览器中输入:http://www.guet.edu.cn/index.html浏览器发送的请求消息中,就会包含Host请求报头域,如下:Host:http://www.guet.edu.cn此处使用缺省端口号80,若指定了端口号,则变成:Host:指定端口号

【HTTP Response header】

同样使用Fiddler 查看Response header, 点击Inspectors tab ->Response tab-> headers 如下图所示

Cache头域
Date作用: 生成消息的具体时间和日期。例如:Date: Sat, 11 Feb 2012 11:35:14 GMT
Expires作用: 浏览器会在指定过期时间内使用本地缓存。例如: Expires: Tue, 08 Feb 2022 11:35:14 GMT
Vary作用:例如: Vary: Accept-Encoding
Cookie/Login 头域
P3P。作用: 用于跨域设置Cookie, 这样可以解决iframe跨域访问cookie的问题。例如: P3P: CP=CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR
Set-Cookie。作用: 非常重要的header, 用于把cookie 发送到客户端浏览器, 每一个写入cookie都会生成一个Set-Cookie.例如: Set-Cookie: sc=4c31523a; path=/; domain=.acookie.taobao.com

Entity头域
ETag作用: 和If-None-Match 配合使用。 (实例请看上节中If-None-Match的实例)例如: ETag: “03f2b33c0bfcc1:0”
Last-Modified:作用: 用于指示资源的最后修改日期和时间。(实例请看上节的If-Modified-Since的实例)例如: Last-Modified: Wed, 21 Dec 2011 09:09:10 GMT
Content-Type作用:WEB服务器告诉浏览器自己响应的对象的类型和字符集,例如:Content-Type: text/html; charset=utf-8;Content-Type:text/html;charset=GB2312;Content-Type: image/jpeg
Content-Length。指明实体正文的长度,以字节方式存储的十进制数字来表示。在数据下行的过程中,Content-Length的方式要预先在服务器中缓存所有数据,然后所有数据再一股脑儿地发给客户端。例如: Content-Length: 19847。
Content-Encoding。WEB服务器表明自己使用了什么压缩方法(gzip,deflate)压缩响应中的对象。例如:Content-Encoding:gzip
Content-Language作用: WEB服务器告诉浏览器自己响应的对象的语言者例如: Content-Language:da
Miscellaneous 头域
Server:作用:指明HTTP服务器的软件信息。例如:Server: Microsoft-IIS/7.5
X-AspNet-Version:作用:如果网站是用ASP.NET开发的,这个header用来表示ASP.NET的版本例如: X-AspNet-Version: 4.0.30319
X-Powered-By:作用:表示网站是用什么技术开发的。例如: X-Powered-By: ASP.NET
Transport头域
Connection。例如: Connection: keep-alive 当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。例如: Connection: close 代表一个Request完成后,客户端和服务器之间用于传输HTTP数据的TCP连接会关闭, 当客户端再次发送Request,需要重新建立TCP连接。
Location头域
Location作用: 用于重定向一个新的位置, 包含新的URL地址 实例请看304状态实例

【HTTP版本有几个】

最早的HTTP版本是0.9,现在已经很少使用了。
而基于0.9版本改进后的是HTTP1.0版本,对应的RFC编号是1945。
现在最常用的则是基于1.0版本改进后的HTTP1.1版本,对应的RFC编号是2616,其最大的改进点就是增加了“持久连接”的内容,同时在缓存控制与多级代理方面也有不小的完善。
【一些高级用法】
1 HTTP1.1中,我们可以在报文中使用Cache-Control域来控制缓存策略;而在HTTP1.0中则可以使用Pragma域来控制。为了确保达到效果,我们往往会在HTTP报文中同时设置Cache-Control:no-cache和Pragma:no-cache
2 在请求报文中,我们可以设置Accept头部域来指明客户端希望接受哪些类型的数据,比如Accept:image/gif,则表明客户端希望接收gif图片数据。当然我们可以设置很多种可接受的类型。
3 在请求报文中,Accept-Charset则是用来设置客户端希望接受的字符集。
4 在请求报文中,Accept-Encoding则是用来指定客户端希望接受的编码类型。
5 在请求报文中,Accept-Language是指明客户端希望接受的语言类型,例如Accept-Language:zh-cn,表明客户端希望得到中文的内容
6 在请求报文中,If-Modified-Since域用作缓存策略。具体的原理是这样的,浏览器本地会缓存一些数据,包括网页、图片等,而且还会同时存储这些缓存数据在服务器端的最后修改时间(Last-Modified)。当浏览器再向服务器端发起这些数据的请求时,会同时把这些数据的最后修改时间通过If-Modified-Since一起传给服务器端,服务器端一旦看到这个头部域,就会先拿这个时间戳和相应资源的最后修改时间比较下,如果相同,就说明这个资源一直以来都没有改动过,于是服务器端就不用再把这个数据重复的传给客户端了,而是直接在响应报文中返回304即可,避免了重复传输带来的带宽消耗。
7 有些同学会感觉疑惑,为什么Last-Modified和If-Modified-Since域都是存储“最后修改时间”的,有啥区别呢。他俩的区别在于,Last-Modified域是响应报文中使用的,由服务器端发给客户端的;而If-Modified-Since则是用在请求报文中的,由客户端发给服务器端的。这两者都是用绝对时间来表示的,所以存在时间同步的问题。那有没有更好的解决办法呢,请继续往下看:)
8 为大家隆重推出Etags和If-None-Match这一对兄弟,他俩的关系和“Last-Modified/If-Modified-Since”的关系一样,Etags(Entity Tags)是用于响应报文中的,而If-None-Match是用于请求报文中的。这对兄弟的好处在于,他们不是以绝对时间来判断数据是否被修改过,而是通过数据的某个属性值来判断,例如数据的MD5值,这样就可以很好的避免时间不同步的问题了。(除了If-None-Match外,请求报文的头部域中还可以用If-Match、If-Range来表示希望获取的Etag值)
9 在响应报文中,可以使用Location头部域来实现重定向,比如更换了域名之后。
10 在HTTP协议里,除了Etags/if-None-Match,Last-Modified/If-Modified-Since外,还有两对这样的兄弟,其一是Server/User-Agent,Server是服务器端用来亮明身份的,而User-Agent是客户端用来亮明身份的;另一对是Set-Cookie和Cookie,Set-Cookie用于服务器端向客户端设置cookie的,而Cookie则是客户端告诉服务器端自己的cookie的。
11 在响应报文中,服务器端可以使用Expires域来告诉客户端最多缓存这个数据到什么时间,如果超过这个时间点的话,客户端就不要再缓存这个数据了,而是向服务器端重新发起新的请求。
12 在响应报文中,服务器端可以使用Set-Cookie头部域向客户端设置cookie。其语法很简单,就是由多个name=value组成的,由分号间隔。例如:
Set-Cookie: ASPSESSIONIDQAQBQQQB=BEJCDGKADEDJKLKKAJEOIMMH; path=/
13 在响应报文中,X-Powered-By头部域表示服务器端使用到的技术名称,例如X-Powered-By: ASP.NET
【结语】
随着你对HTTP协议掌握的越来越深入,你会发现HTTP协议里蕴藏了很多智慧和技巧,如果你和我一样是一名devops的话,对HTTP的了解和深入是必不可少的。
谢谢!

参考文章:
HTTP协议详解


猜你喜欢

转载自blog.csdn.net/maoshengdev/article/details/78228736