计算机网络协议赏析-HTTP
本原创文章属于《Linux大棚》博客。
博客地址为http://roclinux.cn。
文章作者为roc wu
==
【最熟悉的陌生人】
和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),缺省情况下为/
【HTTP请求长什么样儿】
我们先来看一个典型的HTTP请求报文长什么样子:
(我们用/* */注释嵌到请求里,让大家更好的理解每一行语句的含义)
/* 第一行叫做请求行(request),其他的各行都叫做头部行(header) */ /* 请求行包括三个字段:方法字段、URI字段、HTTP版本字段 */ /* 这个例子的请求行,是要做这样一件事:用HTTP协议1.1版本,使用GET方法, 向服务端申请/path/to/page.html资源 */ GET /path/to/page.html HTTP/1.1 /* 下面都属于头部行 */ /* Host用来指定要请求的服务器端主机为roclinux.cn */ Host:roclinux.cn /* Connection:close是要告诉服务器端,我客户端不想使用持久连接, 请服务器端在完成这次请求响应后关闭此连接。虽然这个请求报文中 使用了支持持久连接的HTTP1.1版本,但客户端仍然不想使用持久连接 */ Connection:close /* User-agent域则是用来指定当前这个请求报文是由谁产生的,通常来 说,一般这里设置的是用户所使用的浏览器类型。不要小看这个域,一 些用心的站长,会通过这个域来识别客户,并给不同的客户展示资源的 不同版本呢! */ User-agent:Mozilla/4.0 /* Accept-language域,则是客户端再跟服务器端说“兄弟,如果你那里有 我申请的资源的中文版本,那就把中文版本给我;如果没有中文版本,那 就把你的默认语言版本给我就好了。” */ Accept-language:zh-cn /* 看这里,看这里!或许谁也没有注意到这里,这里有一个空行,而且是必 须有这个空行。这是HTTP协议的硬性规定,不要忘记哦 */
下面,用我精心画的一张图,来说明下请求报文的协议格式:
从上面这个图,应该可以很清晰的看出请求报文的具体格式啦。
【HTTP请求报文中有哪些方法】
HTTP请求方法有很多,我们先走马观花的看看:
GET方法:请求某资源
POST方法:请求某资源的同时附上一些数据
HEAD方法:请求某资源对应的响应报文头
PUT方法:上传一个资源
DELETE方法:删除一个资源
TRACE方法:让服务器回送请求报文,用于调试和排障
OPTIONS:请求服务器性能信息
CONNECT:预留给代理服务器所用
【怎么响应HTTP的请求】
在了解完请求报文的格式之后,你是不是想知道HTTP协议是如何响应请求报文的呢?我们来看一个典型的响应报文:
/* 一个响应报文,一般包括三部分,即状态行、头部行、附属体 */ /* 第一行是状态行,包括三个字段:版本字段、状态码字段、原因短语字段 */ /* 本例中,HTTP协议的响应报文想表达的意思是服务器使用的是HTTP协议1.1版本, 而且找到了客户端所要的资源,且会将响应报文发给客户端,整个过程都很正常 */ HTTP/1.1 200 0K /* 服务器端不会保持住这个连接,而是在回复完这个响应报文之后会断开这个连接 */ Connectlon:close /* 这里记录了这个响应报文被发送出去的时间点 */ Date: Thu, 13 Oct 2005 03:17:33 GMT /* Server域表明这个响应报文是有类Unix操作系统上的Apache服务器发出的,且 Apache的版本是2.0.54 */ Server: Apache/2.0.54 (Unix) /* 用于记录本响应报文中所存的数据的最后修改时间 */ Last—Modified:Mon,22 Jun 1998 09;23;24 GMT /* 指出数据部分的字节数,即单位Byte */ Content—Length:682l /* 指出所包含的数据是HTML文本内容 */ Content—Type:text/html /* 看这里,还得看这里,和请求报文类似,这里也有一个空行,不能省哦 */ /* 这里是实际的响应数据 */ (data data data data …………)
下面,我们同样来看看响应报文的协议格式:
【说说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:服务器现在可能是太忙了,暂时不能给你这个客户端提供服务了,或许稍后会恢复。
【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的了解和深入是必不可少的。
谢谢!
建议继续学习:
- HTTPS, SPDY和 HTTP/2性能的简单对比 (阅读:15911)
- 浅析http协议、cookies和session机制、浏览器缓存 (阅读:15800)
- 从输入 URL 到页面加载完成的过程中都发生了什么事情? (阅读:14502)
- HTTP协议Keep-Alive模式详解 (阅读:10618)
- 各种浏览器审查、监听http头工具介绍 (阅读:6250)
- nginx中对http请求处理的各个阶段分析 (阅读:6070)
- nginx上,http状态200响应,PHP空白返回的问题 (阅读:5515)
- 你不知道的 HTTP (阅读:5369)
- libevent源码浅析: http库 (阅读:4824)
- HTTP幂等性概念和应用 (阅读:4365)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:rocrocket 来源: linux大棚-roclinux.cn
- 标签: HTTP
- 发布时间:2014-04-07 22:57:02
- [53] IOS安全–浅谈关于IOS加固的几种方法
- [52] 如何拿下简短的域名
- [51] 图书馆的世界纪录
- [50] Oracle MTS模式下 进程地址与会话信
- [50] android 开发入门
- [49] Go Reflect 性能
- [46] 【社会化设计】自我(self)部分――欢迎区
- [46] 读书笔记-壹百度:百度十年千倍的29条法则
- [36] 程序员技术练级攻略
- [29] 视觉调整-设计师 vs. 逻辑