一、概述
谈起HTTP协议(超文本传输协议),首先要知道计算机网络的五层协议体系结构(综合了OSI和TCP/IP体系结构的优点),从上层一直到下层分别为:应用层、传输层、网络层、数据链路层、物理层。每一层都有对应的协议,以保证计算机之间能在网络中通信。而HTTP协议则是工作在应用层,为用户浏览Web页面提供支持。这里以一张图来简要说明浏览一个Web页面的过程。
整个过程可以这样概述:域名解析 —> 建立TCP连接(三次握手)—> 客户端发送HTTP请求 —> 服务器端返回HTTP响应,浏览器得到html代码 —> 浏览器解析代码并请求代码中的资源(如css、js、图片等)—> 浏览器渲染页面并呈现给用户 —> 断开TCP连接(四次挥手)。具体过程可以参考这篇博客:https://blog.csdn.net/sinat_21455985/article/details/53508115。
二、HTTP协议的特点
谈起HTTP协议,我们首先要知道HTTP协议是一种无状态的协议,即HTTP协议自身不对请求和响应之间的通信状态进行保存,也就是说在HTTP这个级别,协议对于发送过来的请求或响应不做持久化处理。当然,这样做的好处很明显,那就是能更快地处理大量事务,确保协议的可伸缩性。不过,随着Web的不断发展,这样做不能满足复杂的业务,比如登录一个购物网站,即使用户跳转到了其他页面,也需要继续保持登录状态,因为这样服务器才能掌握是哪个用户发送了什么请求。所以,面对这样的业务,需要实现保存状态的功能,于是引入了Cookie技术,有了Cookie再使用HTTP协议进行通信,就可以管理状态了。有关Cookie的详细内容,稍后详解。
三、HTTP协议中可使用的方法
当浏览一个Web页面时,客户端要向服务器发送请求,而这个请求中要包含请求的方法。HTTP协议/1.1支持的方法有:GET、POST、PUT、DELETE、HEAD、OPTIONS、TRACE、CONNECT。
①GET方法(获取资源)
用来请求访问被URI标识的资源,指定的资源被服务器解析以后返回响应内容,如下图:
②POST方法(传输实体主体)
主要用于传输实体的主体,虽然用GET方法也能传输实体的主体,但一般不用GET方法进行传输。虽说POST方法和GET方法很相似,但POST的主要目的不是获取响应的主体内容。用该方法的通信场景如下图所示:
③PUT方法(传输文件)
用于传输文件,就像FTP协议的文件上传一样,要求在请求报文的主体包含文件内容,然后保存到请求URI指定的位置。由于HTTP/1.1的PUT方法自身不带验证机制任何人都可以上传文件,存在安全问题,因此一般的Web网站不使用这个方法。若配合Web应用程序自身的验证机制,或架构设计采用REST标准的同类Web网站,就可能开放使用PUT方法。用该方法的通信场景如下图所示:
④DELETE(删除文件)
用于删除文件,按请求的URI删除指定资源。与PUT方法一样,HTTP/1.1的DELETE方法自身也不带验证机制,所以一般的Web网站也不使用DELETE方法。当配合Web应用程序的验证机制,或遵守REST标准时有可能会开放使用。用该方法的通信场景如下图所示:
⑤HEAD(获得报文首部)
HEAD方法和GET方法一样,只是HEAD方法不返回报文主体部分。主要用于确认URI的有效性以及资源更新的日期时间等。用该方法的通信场景如下图所示:
⑥OPTIONS(询问支持的方法)
用于查询针对请求URI指定的资源支持的方法。用该方法的通信场景如下图所示:
⑦TRACE(追踪路径)
用于让 Web 服务器端将之前的请求通信环回给客户端的 方法。 发送请求时,在 Max-Forwards 首部字段中填入数值,每经过一个 服务器端就将该数字减 1,当数值刚好减到 0 时,就停止继续传输,最后接收到请求的服务器端则返回状态码 200 OK 的响应。客户端通过TRACE方法可以查询发送出去的请求是怎样被加工修改/篡改的。这是因为,请求想要连接到源目标服务器可能会通过代理 中转,TRACE 方法就是用来确认连接过程中发生的一系列操作。但是,TRACE 方法本来就不怎么常用,再加上它容易引发 XST (Cross-Site Tracing,跨站追踪)攻击,通常就更不会用到了。用该方法的通信场景如下图所示:
⑧CONNECT(要求用隧道协议连接代理)
CONNECT 方法要求在与代理服务器通信时建立隧道,实现用隧道 协议进行 TCP 通信。主要使用SSL(Secure Sockets Layer,安全套接层)和TLS(Transport Layer Security,传输层安全)协议把通信内容加密后经网络隧道传输。CONNECT 方法的格式为:CONNECT 代理服务器名:端口号 HTTP版本。用该方法的通信场景如下图所示:
总结
总的来说,HTTP协议中的这些方法本质上都是基于TCP进行通信的,而HTTP协议只是制定了不同的通信规则。而在面试中,面试官经常会问到一个问题:HTTP请求中GET请求和POST请求有什么不同?假如你这样回答:
答:GET请求和POST请求不同的地方在于:①GET请求会被浏览器主动缓存,而POST请求不会;②当页面回退时,GET请求不会再次向服务器提交请求,而POST请求会;③GET请求可以被存做书签,而POST请求不可以;④GET请求在URL中传送的参数是有长度限制,而POST请求没有;⑤GET请求的参数会暴露在URL中,而POST请求不会,所以GET方法相较于POST方法来说不安全,一般不用于传递敏感信息;⑥GET请求参数会被完整的保存在浏览器记录里,而POST请求不会;⑦GET请求的参数通过URL传递而POST请求则是放在Request Body里;⑧GET请求的参数只接受ASCII字符,而POST没有限制;⑨GET请求只能进行URL编码,而POST支持多种编码方式。
当然,你这样回答是完全没有问题的,但这只是两者表面上的区别,那么二者实质上有什么区别呢?其实,GET和POST实质上没有区别,因为GET和POST都是HTTP协议中两种发送请求的方法,而HTTP是基于TCP/IP的在万维网中通信的协议,所以GET和POST请求都是基于TCP连接的,GET能做的事情POST也能做到,比如你要把GET请求加上Request Body,给POST带上URL参数,技术上是完全可以实现的。
那么,是什么导致了出现了GET和POST请求,而不是大家都用一个通用的请求呢?因为在万维网的世界里,TCP就像汽车,浏览器像运输公司。我们用汽车运输数据,它很可靠,不会发生丢件少件的现象(如果出现了,则重新运输)。但是如果路上跑的都是一模一样的汽车,当汽车运输的数据到达运输公司,运输公司怎么区分这些汽车呢?也就是说各个汽车所运输的数据有什么不同。于是HTTP给汽车进行了分类,GET和POST等方法应运而生。于是不同类别的汽车,其功能上有了不同。但是它们实质上都是汽车。
还有一点,GET和POST还有一个重大的不同,那就是GET请求发送的是一个TCP数据包,而POST请求发送两个。具体来说,使用GET请求时,浏览器会把http header和data一起发送出去,而POST请求会先发送 http header,直到服务器端返回100 continue,浏览器再发送data。因为POST要发送两次数据包,时间上要多消耗一点,看起来GET比POST有效,因此Yahoo团队有推荐用GET替换POST来优化网站性能。但这是一个坑!跳入需谨慎。为什么?原因如下:①GET与POST都有自己的语义,不能随便混用;②据研究,在网络环境好的环境下,发一次和发两次包的时间差别基本可以无视,而在网络环境差的情况下,两次包的TCP在验证数据包的完整性上,有非常大的优点;③并不是所有的浏览器发送POST请求都发送两次包,Firefox就只发送一次。
四、HTTP实现持久连接
在初始版本的HTTP协议中,每进行一次HTTP通信就要断开一次TCP连接(如下图)。
以当年的通信情况来说,因为都是些容量很小的文本传输,所以即使这样也没有多大的问题,可是随着HTTP的普及,文档中包含大量图片的情况多了起来。比如,现在打开一个Web网站的页面,页面中包含大量的图片,在发送请求访问HTML页面资源的同时,就会请求该页面中包含的图片资源,因此每次请求都会造成无谓的TCP连接建立与断开,增加通信开销。其通信过程如下图:
于是,持久连接应运而生,持久连接的特点是:只要任意一端没有明确提出断开连接,则保持TCP连接状态。在HTTP1.0中,没有默认支持持久连接,而在HTTP1.1中所有连接默认都是持久连接。持久连接通信过程如下图:
实现了持久连接以后,使得多数请求以管线化方式发送成为可能。从前发送请求后,需要等待并收到响应才能发送下一个请求。管线化技术出现以后,不用等待响应就可以直接发送下一个请求。这样就能做到同时并行发送多个请求,而不需要一个接一个的等待响应了。所以,管线化技术比持久连接还快,请求数越多,时间差就越明显。使用管线化技术进行通信的过程如下:
五、使用Cookie的状态管理
之前已经提到过,HTTP是无状态的协议,它不对之前发生过的请求和响应的状态进行管理。也就是说,无法根据之前的状态进行本次的请求处理。假设要求登录认证的Web页面本身无法进行状态的管理(不记录已经登录的状态),那么每次跳转新页面不是要再次登录,就是要在每次请求报文中附加参数来管理登录状态。
当然,无状态有无状态的优点,比如:由于不必保存状态,自然可减少服务器的CPU及内存消耗。从另一个侧面来说,也正是因为HTTP协议自身是非常简单的,所以才会被应用到各种场景里。
于是,在保留无状态协议这个特征的同时,又要解决上述的问题,便引入了Cookie技术。Cookie技术是通过在请求和响应报文中写入Cookie信息来控制客户端状态。使用Cookie实现客户端状态控制的过程如下图:
具体的请求和响应的报文如下图:
讨论
1、如果在客户端禁用了Cookie,那么这时候怎么实现客户端状态的控制呢?
通过前面的介绍,我们了解到Cookie的作用之一就是作为SessionID的容器,当然Cookie和Session在这里没有展开,更多的关于二者的联系与区别请查看这篇博客http://www.cnblogs.com/andy-zhou/p/5360107.html。那么,如果禁用了Cookie,SID字段客户端该怎么存储以及传递到服务器呢?这里常用的方法就是URL重写。顾名思义,URL重写即是每一次页面跳转时,对跳转的URL进行重写(在URL里面加上SID值),这样做的话SID就不用回传给客户端,只是每次页面跳转把SID值写到URL中。总之,以前的SID值是存到Cookie中并回传给客户端,现在SID值不回传给客户端而是附加在URL中,即SID的容器由Cookie变为了URL。
2、面试常问问题,Cookie和Session的区别与联系?
我想只要解决了第一个问题,那么这个问题就很easy了。区别:①Cookie是把用户的数据存到本地,而Session则是把用户的数据存在服务器;②单个Cookie的大小不能超过4K,而单个Session的大小与服务器内存有关(理论上服务器内存足够大可以无限制存储数据,但实际肯定是只存重要的数据);③Cookie不安全,如果黑客入侵你的电脑,可以分析你电脑里的Cookie并进行Cookie欺骗,而Session会更安全。联系:①Cookie没有禁用的情况下,Cookie会作为SID值的容器;②可以把一些敏感、重要的信息放在Session里,其他信息放在Cookie中。