作为一个前端,如果对一个网页从发起请求到返回数据这期间具体发生了什么都不知道的话,那不是一个好前端。最近,读了图解http,以及有关http相关的文章,还有自己也下载了wireshark抓包工具,实际观察了一下这个过程,下面就此做些总结。
一.从输入一个url到返回数据,中间到底发生了什么?
假设,我们在浏览器输入http://www.baidu.com:80/index.html,假设解析出的ip地址是202.43.78.3
1.浏览器解析出主机名
解析出的主机名是www.baidu.com
2.浏览器查询这个主机名的ip地址(dns)
dns解析的作用就是把域名解析成ip地址,这样才能在广域网路由器转发报文给目标ip,不然路由器不知道要把报文发给谁。下面就讲下大概的过程,不会涉及太多细节。(以chrome为例子)
(1)浏览器启动时,首先浏览器会去操作系统获取dns服务器地址,然后把这个地址缓存下来。同时浏览器还会去读取和解析hosts文件,同样放到缓存中。浏览器对解析过的域名和ip地址,都会保存着这两者的映射关系。(存到cache中)
(2)当解析域名的时候,首先浏览器会去cache中查找有没有缓存好的映射关系,如果没有的话,就去hosts文件中查找,如果也没有的话,浏览器就会发起请求去dns服务器缓存查询了,如果缓存里面也没有,那最后就是dns服务器去查询了。
3.浏览器获取端口号
4.浏览器向目标ip地址发起一条到202.43.78.3:80的tcp连接
为了传输的可靠性,tcp协议要有三次握手过程:
(1)首先浏览器会向服务器发起一个连接请求
(2)服务器会对连接请求做出响应,表示同意建立连接
(3)浏览器收到响应后,再告知对方,它知道服务器同意它建立连接了。
5.数据包在ip层传输,通过多台计算机和网络设备中转,在中转时,利用中转设备的mac地址搜索下一个中转目标(采用ARP协议,根据通信方的ip地址就可以反查出对应的mac地址),直到目标ip地址。
6.数据链路层处理网络连接的硬件部分,比如网卡,找到服务器的网卡
7.浏览器向服务器发送一条http报文
每一条http报文的组成:
起始行+首部+主体(可选)
起始行:http/1.0 200 ok (一般包括http版本,返回状态码,返回码原因)
首部:content-type:text/plain content-length:19
主体:name=jane
8.服务器接受客户端请求,进行一些处理,返回响应报文
web服务器接收到请求之后,实际上会做些什么呢?
(1)建立连接,如果接受一个客户端连接,就建立连接,如果不同意,就将其关闭。
(2)接收请求,读取http请求报文
(3)访问资源,访问报文中指定的资源
(4)构建响应,创建带有首部的http响应报文
(5)发送响应,将响应回送给客户端
9.浏览器读取http响应报文
10.浏览器关闭连接
看了上面的一个简单过程,大家会不会有这样一个问题,难道每次发起一个http请求,都要建立一次tcp连接吗,我们经常写的并发ajax请求,每条请求都是各自独立建立的tcp连接?一条tcp连接建立之后,是什么时候关闭的?带着这些问题,看看下面要讲的http的特性
二. http的特性
1.http是不保存状态的协议
http协议是一种无状态的协议,意思就是说它不会对每次的请求和响应之间的通信状态进行保存。你之前发过的任何请求的信息,没有任何记录。之所以这样设计,也是为了让http变得比较简单,可以处理大量事物。但是无状态的特性,也会导致一些问题,比如说一个用户登录一家网站之后,跳到另一个页面,应该还保持着登录状态,所以后面就出了cookie状态管理技术。相信大家应该都很熟悉了。
2.请求只能从客户端开始。客户端不可以接收除响应以外的指令
服务器必须等待客户端的请求,才能给客户端发送响应数据,所以说服务器是不能主动给客户端推送数据的。对于一些实时监控的功能,常常用websocket来代替
3.没有用户认证,任何人都可以发起请求
在http协议通信时,是不存在确认通信方的处理步骤的,任何人都可以发起请求。另外,服务器只要收到请求,无论是谁,都会返回一个响应。所以会存在伪装的隐患。后面出现的https就可以解决这个问题。
4.通信使用的是明文
5.无法证明报文完整性
6.可任意选择数据压缩格式,非强制压缩发送
7.http持久连接和并行连接
一开始,http请求是串行的,一个http请求,就会建立一条tcp连接,浏览器收到响应之后,就会断开连接。等上一个请求回来了,下一个请求才能继续请求。这样做的缺点是,比较耗时间和内存,后面就出现了下面一系列的优化连接性能的方法。
(1)并行连接:
原理:通过多条tcp连接发起并发的http请求
并行连接可以同时发起多个http请求,每次发起一个http请求,就会建立一个tcp连接。每个http请求是独立的,不会相互等待,这样做,很可能会提高页面的加载速度,因为人们会看到页面上面,很多个东西会同时出现,所以感觉页面加载变快了。实际上有时候是真的变快了,因为它是并行工作的。但是有时候不是真的快了。比如说,客户端的网络带宽不足时,(浏览器是通过一个28kbps的modem连接到因特网上去的),如果并行加载多个请求,每个请求就会去竞争这个有限的带宽,每个请求就会以比较慢的速度加载。这样带来的性能提升就很小。
(2)持久连接:
原理:重用tcp连接,以消除连接及关闭时延
从http1.1开始,就允许当http响应结束后,tcp连接可以保持在打开状态,以便给未来的http请求重用现在的连接。那么,这个tcp连接什么时候会关闭呢,一般情况下,40s内,如果没有新的请求,就会关闭。
(3)管道化连接
原理:通过共享的tcp连接发起并发的http请求
并行连接可以提高复合页面的传输速度,但是也有许多缺点,比如每次都会建立一次tcp连接,会耗费时间和带宽。持久连接的优势就是降低了时延和tcp的连接数量。但是持久连接可能会导致的一个问题是,可能会累积大量的空闲连接。耗费资源。
持久连接和并行连接配合使用才是最高效的方式。
一般浏览器会限制,同个域名下的并行连接的个数是4个,即打开少量的并行连接,其中每个都是持久连接。这也是现在用的最多的方式。