随着信息化程度越来越高,上网对于任何人来说都不再是一件难事。
当我们输入一个网址:www.zhihu.com/people/shan…,轻敲一下回车,一个页面就展现在了我们面前
那么从我们输入一个网址到页面展现的过程到底发生了什么呢?作为经典面试题之一,接下来就让我们再重温一下。
总体来说分为以下几个过程:
- 输入网址
- DNS解析
- 建立TCP/IP链接‘
- 发送HTTP请求
- 服务器处理请求
- 服务器返回HTTP响应
- 浏览器渲染页面并展现
- 断开连接
接下来展开讲一讲
一、输入网址(什么是URL?)
当我们想要打开一个页面时,很简单的会想到去输入一个网址,比如说(www.baidu.com)
这里俗称的网址其实就是URL(Uniform Resource Locator),即统一资源定位符
我们以一个网址(哦不对,我们要用更专[装]业[杯]的说法,URL)为例,解释一下它各部分的组成:
http://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocument
http :http是协议(Protocol),它表明了浏览器使用何种协议,有http、https、ftp、mailto等,其中https是加密认证版的http(详见《图解HTTP》)
www. example.com :这是域名(Domain name),它表明正在请求哪个Web服务器,其中www是主机名(host)
80:这是端口(Port),它表示用于访问Web服务器上的资源的“门”。如果Web服务器使用HTTP协议的标准端口(HTTP为80,HTTPS为443)来授予其资源的访问权限,则通常会被忽略。否则是强制性添加。
/path/to/myfile.html :是网络服务器上资源的路径(Path to the file)。在Web的早期阶段,像这样的路径表示Web服务器上的物理文件位置。
?key1=value1&key2=value2 :是提供给网络服务器的额外参数(Parameters)。 这些参数是用 &符号分隔的键/值对列表。
#SomewhereInTheDocument:是资源本身的另一部分的锚点(Anchor)。 锚点表示资源中的一种“书签”,给浏览器显示位于该“加书签”位置的内容的方向。
总结来说,一个完整的URL组成是这样的:
protocol://host.domain:port /path to the file/?parameters#anchor
当然在我们真正输入和操作的时候很多东西会被自动补全,也有很多部分可以省略,比如端口、协议等
二、DNS解析
输入网址(URL)这一步我们很好理解,但是接下来所谓的域名解析是什么呢?又是为什么要进行域名解析呢?
在回答这些问题之前,我们先来熟悉一个概念:IP地址
IP 地址(Internet Protocol Address)是互联网协议特有的一种地址,它是 IP 协议提供的一种统一的地址格式。IP 地址为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
像192.168.59.0就是一个主机IP地址
对于计算机来说,它既可以被赋予IP地址,又可以被赋予主机名和域名。但我们通常使用域名(www.baidu.com)去访问想要的网站,为什么?这是因为对于我们来说去理解、操作和记忆域名远比使用IP地址来的更方便。但是对于计算机来说则不然,理解域名相对来说是件更复杂耗时的事情。
再通俗的来说,IP地址好比是你家的门牌号,域名好比“XXX家”这种笼统的称呼,我们更喜欢去记后者,但对于快递员来说,他并不认识你,因此记忆前者对他来说是件更有帮助的事。
为了解决上述的问题,DNS服务应运而生,它通过我们输入的域名去查找对应的IP地址,或逆向从 IP 地址反查域名的服务。
所谓的DNS服务,就是和HTTP协议一样位于应用层的协议,提供域名到IP地址之间的解析服务。
由图可以看出,当我们输入域名,DNS服务就会根据这个域名把对应的IP地址找出来告诉计算机,但是这些IP地址是怎么被找出来的呢?换句话说,DNS是按照什么样的顺序找到这个域名的呢(总不应该是大海捞针吧)?
其实是按以下顺序来的
- 浏览器缓存:看看之前有没有访问过这个域名,浏览器会按照一定的频率缓存 DNS 记录。
- 系统缓存:如果浏览器缓存中找不到需要的 DNS 记录,那就去操作系统中找。
- 路由器缓存:电脑可能换了,不过路由器也有 DNS 缓存。
- ISP 的 DNS 服务器:ISP 是互联网服务提供商的简称(就是中国移动、中国电信啥的),ISP 有专门的 DNS 服务器应对 DNS 查询请求。
- 根服务器:ISP 的 DNS 服务器还找不到的话,它就会向根服务器发出请求,进行递归查询(DNS 服务器先问根域名服务器.com 域名服务器的 IP 地址,然后再问.baidu 域名服务器,依次类推
三、建立TCP/IP链接
当拿到域名对应的IP地址之后,浏览器会以一个随机端口向服务器的WEB程序的80/443端口发起TCP的连接请求。这个连接请求到达服务器端后(这中间通过各种路由设备,局域网内除外),进入到网卡,然后是进入到内核的TCP/IP协议栈(用于识别该连接请求,解封包,一层一层的剥开),还有可能要经过Netfilter防火墙(属于内核的模块)的过滤,最终到达WEB程序,最终建立了TCP/IP的连接。
我们在知识补充部分讲了一些关于通信的基础,知道了TCP协议属于传输层,顾名思义这是个有助于传输并且还具有极高可靠性的协议,即将大块数据分割成报文段的形式进行管理,同时呢他能够确认数据是否送达对方。那具体是怎么确认,为什么说他具有极高可靠性呢?这也就是我们接下来说的三次握手:
即:
- 客户端发送 SYN=1的询问报文给服务器端,seq是n,进入 SYN_SENT 状态。
- 服务器端回应一个ACK=1、SYN=1 的应答+询问报文。应答号ack是n+1,询问号seq是m,进入 SYN_RCVD 状态。
- 客户端收到后,回应一个 ACK=1的应答报文,应答号是m+1,进入 Established 状态。
通俗来说,可以把他们理解为对讲机通话:
- 准备好了吗,老哥,我要发送数据了? (SYN=1,seq=100 )
- 老妹儿,我收到你的询问了,并且准备好了,老妹儿,快发吧。(ACK=1, ack=101. SYN=1, seq=200)
- 好嘞,那我发了啊。(ACK=1, ack=201)
为什么要三次握手 :
谢希仁著《计算机网络》中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。
(TCP 为什么是三次握手,而不是两次或四次? - 山尽的回答 - 知乎 www.zhihu.com/question/24…)
感觉第二个是更本质的讲法,谢希仁老师的更像是个例子,望大佬们懂得可以指点一下
四、发送HTTP请求
TCP 三次握手结束后确认数据传输可靠后,开始发送 HTTP 请求报文。 请求报文的结构如下图所示:
请求行
一个例子:GET http://www.example.com/dir/indec.html HTTP/1.1
包含请求的方法:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE。
URL:由 <协议>://<主机>:<端口>/<路径>?<参数> 组成
协议版本:即 http 版本号
首部行:用来说明浏览器、服务器或报文主体的一些信息
实体主体:一般不用这个字段
一个完整的HTTP请求报文例子:
五、服务器处理请求
服务器给浏览器响应一个301永久重定向响应,这样浏览器就会访问“www.google.com/” 而非“google.com/”。
为什么服务器一定要重定向而不是直接发送用户想看的网页内容呢?其中一个原因跟搜索引擎排名有关。如果一个页面有两个地址,就像www.yy.com/和yy.com/,搜索引擎会认为它们是两个网站,结果造成每个搜索链接都减少从而降低排名。而搜索引擎知道301永久重定向是什么意思,这样就会把访问带www的和不带www的地址归到同一个网站排名下。还有就是用不同的地址会造成缓存友好性变差,当一个页面有好几个名字时,它可能会在缓存里出现好几次。
1)301和302的区别。
301和302状态码都表示重定向,就是说浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址,这个地址可以从响应的Location首部中获取(用户看到的效果就是他输入的地址A瞬间变成了另一个地址B)——这是它们的共同点。
他们的不同在于。301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了),搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址;
302表示旧地址A的资源还在(仍然可以访问),这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容而保存旧的网址。 SEO302好于301
2)重定向原因:
(1)网站调整(如改变网页目录结构);
(2)网页被移到一个新地址;
(3)网页扩展名改变(如应用需要把.php改成.Html或.shtml)。
这种情况下,如果不做重定向,则用户收藏夹或搜索引擎数据库中旧地址只能让访问客户得到一个404页面错误信息,访问流量白白丧失;再者某些注册了多个域名的网站,也需要通过重定向让访问这些域名的用户自动跳转到主站点等。
经过前面的重重步骤,我们终于将我们的http请求发送到了服务器这里,其实前面的重定向已经是到达服务器了,那么,服务器是如何处理我们的请求的呢?
后端从在固定的端口接收到TCP报文开始,它会对TCP连接进行处理,对HTTP协议进行解析,并按照报文格式进一步封装成HTTP Request对象,供上层使用。
一些大一点的网站会将你的请求到反向代理服务器中,因为当网站访问量非常大,网站越来越慢,一台服务器已经不够用了。于是将同一个应用部署在多台服务器上,将大量用户的请求分配给多台机器处理。此时,客户端不是直接通过HTTP协议访问某网站应用服务器,而是先请求到Nginx,Nginx再请求应用服务器,然后将结果返回给客户端,这里Nginx的作用是反向代理服务器。同时也带来了一个好处,其中一台服务器万一挂了,只要还有其他服务器正常运行,就不会影响用户使用。
六、返回HTTP响应
当服务器收到我们的请求之后,他会生成一个响应,以响应报文的形式返回客户端,这里与请求发出的过程类似,不在赘述
有不同的是,在响应报文的开始行不再是请求行,而是状态行
状态行包含:协议版本,状态码,解释状态码的简单短语
状态码规则如下: 1xx:指示信息--表示请求已接收,继续处理。 2xx:成功--表示请求已被成功接收、理解、接受。 3xx:重定向--要完成请求必须进行更进一步的操作。 4xx:客户端错误--请求有语法错误或请求无法实现。 5xx:服务器端错误--服务器未能实现合法的请求。
常见状态码:202(接受)、400(错误的请求)、404(not found)
七、浏览器渲染页面并展现
当客户端拿到响应文本经过层层解析,最终浏览器拿到HTML响应报文后,便开始渲染页面
遵循以下的步骤
- 解析 HTML 标签, 构建 DOM 树
- 解析 CSS, 构建 CSSOM 树
- 把 DOM 和 CSSOM 组合成 渲染树 (render tree)
- 在渲染树的基础上进行布局, 计算每个节点的几何结构
- 把每个节点绘制到屏幕上 (painting)
两个概念:
reflow:DOM节点中的各个元素都是以盒模型的形式存在,这些都需要浏览器去计算其位置和大小等,这个过程称为relow
repaint:当盒模型的位置,大小以及其他属性,如颜色,字体,等确定下来之后,浏览器便开始绘制内容,这个过程称为repain
reflow和repain过程是非常消耗性能的,因此我们尽量减少reflow和repaint的出现。
因此,尽量一次成型修改样式、给动画使用绝对定位可以减少reflow、DOM离线后修改
js阻塞加载和解析:
浏览器在解析过程中,如果遇到请求外部资源时,如图像,iconfont,JS等。浏览器将重复上述1-6过程来下载该资源。请求过程是异步的,并不会影响HTML文档进行加载,但是当文档加载过程中遇到JS文件,HTML文档会挂起渲染过程,不仅要等到文档中JS文件加载完毕还要等待解析执行完毕,才会继续HTML的渲染过程。原因是因为JS有可能修改DOM结构,这就意味着JS执行完成前,后续所有资源的下载是没有必要的,这就是JS阻塞后续资源下载的根本原因。CSS文件的加载不影响JS文件的加载,但是却影响JS文件的执行。JS代码执行前浏览器必须保证CSS文件已经下载并加载完毕。
八、断开连接
- 客户端发送一个 FIN ,告诉服务器想关闭连接。
- 服务器收到这个 FIN ,发回一个 ACK。
- 服务器通知应用程序关闭网络连接,应用程序关闭后通知服务器。服务器发送一个 FIN 给客户端 。
- 客户端发回 ACK 报文确认。
为什么挥手要四步 :
这是因为服务端的 LISTEN 状态下的 SOCKET 当收到客户端建立连接请求的SYN 报文后,它可以把 ACK 和 SYN ( ACK 起应答作用,而 SYN 起同步作用)放在一个报文里来发送。但关闭连接时,当服务器收到客户端的 FIN 报文通知时,服务器只能发一个回应报文ACK:“哦,我知道了”,然后通知应用程序。应用程序完成全部数据发送并确定可以终止了,服务器才能发送FIN告诉客户端可以真正断开连接了。所以这一步ACK报文和FIN报文需要分开发送,因此多了一个步骤。
知识补充
通信基础知识
为了更好的理解这一部分,我们有必要简要说明一些网络基础。
通常使用的网络是在TCP/IP协议族的基础上实现的,包括我们使用的HTTP协议也是它的其中一个子集。我们知道计算机与网路设备间要进行通信就必须基于相同的方法(比如传输数据的方式,通信由谁发起等),而定义相同的方法需要一套规则,这个规则也就是协议(比如说HTTP)。
而TCP/IP协议族就是这样协议的集合
不同于国际标准(OSI)(但其实是TCP/IP得到了广泛使用)的七层分层概念,TCP/IP只有四层:应用层、传输层、网络层、数据链路层
- 应用层:决定了向用户提供应用服务时的活动。TCP/IP里预存了一些这样的应用服务,比如DNS、FTP、HTTP等
- 传输层:提供处于网络连接中的两台计算机之间的数据传输,在这一层有两个协议(TCP和UDP)
- 网络层:用来处理在网络上流动的数据包,规定数据到达对方计算机的传输路线
- 数据链路层:硬件部分,比如网卡、驱动、光纤等物理可见的部分,看得到摸得到的硬件均属于这一层
分层带来的好处是显而易见的:比如各层相互独立、灵活性好、易于维护等
那么当我们想要打开一个网页,大概经历了一个怎么样的过程呢?
如下图所示:
利用TCP/IP协议族进行网络通信时,会利用上述分层的顺序与对方进行通信,发送端从应用层发出命令往下走,而接收端则是从数据链路层收到数据往上走。
以我想打开一个知乎页面,即发送HTTP请求来说:
客户端:
- 应用层(其中的HTTP协议)发出HTTP请求
- 传输层(TCP协议)为了传输方便,对上述的HTTP请求报文进行分割,并在各个被分割的部分打上标记序号和端口号,同时打上属于自己的记号
- 网络层(IP协议)增加作为通信目的地的MAC地址,同时打上属于自己的记号
- 数据链路层发送请求,同时打上属于自己的记号
服务器:
- 数据链路层接收数据,并去掉记号
- 网络层读取并去掉记号
- 传输层读取并去掉记号
- 应用层读取最终的请求