1.3 HTTP协议解析
B/S网络架构的核心是HTTP协议,掌握HTTP协议对一个从事互联网工作的程序员来说非常重要,也许你已经非常熟悉HTTP协议,这里除了简单介绍HTTP协议的基本知识外,还将侧重介绍实际使用中的一些心得,后面将以实际使用的场景为例进行介绍。
要理解HTTP协议,最重要的就是要熟悉HTTP协议中的HTTP Header,HTTP Header控制着互联网上成千上万的用户的数据的传输。最关键的是,它控制着用户浏览器的渲染行为和服务器的执行逻辑。例如,当服务器没有用户请求的数据时就会返回一个404状态码,告诉浏览器没有要请求的数据,通常浏览器就会展示一个非常不愿意看到的该页面不存在的错误信息。
常见的HTTP请求头和响应头分别如表1-1和表1-2所示,常见的HTTP状态码如表1-3所示。
表1-1 常见的HTTP请求头
表1-2 常见的HTTP响应头
表1-3 常见的HTTP状态码
要看一个HTTP请求的请求头和响应头,可以通过很多浏览器插件来看,在Firefox中有Firebug和HttpFox,Chrome自带的开发工具也可以看到每个请求的请求头信息(可用F12快捷键打开),IE自带的调试工具也有类似的功能。
1.3.1 查看HTTP信息的工具
有时候我们需要知道一个HTTP请求到底返回什么数据,或者没有返回数据时想知道是什么原因造成的,这时我们就需要借助一些工具来查询这次请求的详细信息。
在Windows下现在主流的浏览器都有很多工具来查看当前请求的详细HTTP协议信息,如在Firefox浏览器下,使用最多的是Firebug,如图1-5所示。
图1-5 Firefox浏览器下HTTP协议的信息
还有一个HttpFox工具提供的信息更全,如图1-6所示,所有HTTP相关信息都可以一目了然。
图1-6 HttpFox工具显示的HTTP协议的信息
Chrome浏览器下也有一些类似的工具,如Google自带的调试工具,同样可以查看到这次请求的相关信息,如图1-7所示。
图1-7 Google自带的调试工具显示的HTTP协议的信息
Chrome下也有类似的Firebug工具,但是还不够完善。
IE从7.0版本开始也提供了类似的HTTP调试工具,如自带的开发人员工具可以通过F12键打开,HttpFox插件也有IE版本,读者可以试着安装一下。
1.3.2 浏览器缓存机制
浏览器缓存是一个比较复杂但是又比较重要的机制,在我们浏览一个页面时发现有异常的情况下,通常考虑的就是是不是浏览器做了缓存,所以一般的做法就是按Ctrl+F5组合键重新请求一次这个页面,重新请求的页面肯定是最新的页面。为什么重新请求就一定能够请求到没有缓存的页面呢?首先是在浏览器端,如果是按Ctrl+F5组合键刷新页面,那么浏览器会直接向目标URL发送请求,而不会使用浏览器缓存的数据;其次即使请求发送到服务端,也有可能访问到的是缓存的数据,比如,在我们的应用服务器的前端部署一个缓存服务器,如Varnish代理,那么Varnish也可能直接使用缓存数据。所以为了保证用户能够看到最新的数据,必须通过HTTP协议来控制。
当我们使用Ctrl+F5组合键刷新一个页面时,在HTTP的请求头中会增加一些请求头,它告诉服务端我们要获取最新的数据而不是缓存。
如图1-8所示,这次请求没有发送到服务端,使用的是浏览器缓存数据,按Ctrl+F5组合键刷新后,如图1-9所示。
图1-8 HTTP的请求头返回缓冲数据
图1-9 按Ctrl+F5组合键刷新页面时HTTP的请求头返回数据
这次请求时从服务端返回的数据,最重要的是在请求头中增加了两个请求项Pragma:no-cache和Cache-Control:no-cache。为什么增加了这两项配置项,它们有什么作用?
1.Cache-Control/Pragma
这个HTTP Head字段用于指定所有缓存机制在整个请求/响应链中必须服从的指令,如果知道该页面是否为缓存,不仅可以控制浏览器,还可以控制和HTTP协议相关的缓存或代理服务器。HTTP Head字段有一些可选值,这些值及其说明如表1-4所示。
表1-4 HTTP Head字段的可选值
Cache-Control请求字段被各个浏览器支持得较好,而且它的优先级也比较高,它和其他一些请求字段(如Expires)同时出现时,Cache-Control会覆盖其他字段。
Pragma字段的作用和Cache-Control有点类似,它也是在HTTP头中包含一个特殊的指令,使相关的服务器来遵守,最常用的就是Pragma:no-cache,它和Cache-Control:no-cache的作用是一样的。
2.Expires
Expires通常的使用格式是Expires:Sat, 25 Feb 2012 12:22:17 GMT,后面跟着一个日期和时间,超过这个时间值后,缓存的内容将失效,也就是浏览器在发出请求之前检查这个页面的这个字段,看该页面是否已经过期了,过期了就重新向服务器发起请求。
3.Last-Modified/Etag
Last-Modified字段一般用于表示一个服务器上的资源的最后修改时间,资源可以是静态(静态内容自动加上Last-Modified字段)或者动态的内容(如Servlet提供了一个getLastModified方法用于检查某个动态内容是否已经更新),通过这个最后修改时间可以判断当前请求的资源是否是最新的。
一般服务端在响应头中返回一个Last-Modified字段,告诉浏览器这个页面的最后修改时间,如Last-Modified:Sat, 25 Feb 2012 12:55:04 GMT,浏览器再次请求时在请求头中增加一个If-Modified-Since:Sat, 25 Feb 2012 12:55:04 GMT字段,询问当前缓存的页面是封面
与Last-Modified字段有类似功能的还有一个Etag字段,这个字段的作用是让服务端给每个页面分配一个唯一的编号,然后通过这个编号来区分当前这个页面是否是最新的。这种方式比使用Last-Modified更加灵活,但是在后端的Web服务器有多台时比较难处理,因为每个Web服务器都要记住网站的所有资源,否则浏览器返回这个编号就没有意义了。