解析在浏览器地址栏输入一个URL后发生了什么

目录
  • 一、前言
  • 二、解析 URL
  • 三、浏览器封装 HTTP 请求报文
  • 四、DNS 域名解析获取 IP 地址
  • 五、建立 TCP 连接
  • 六、浏览器发送请求
  • 七、负责传输的 IP 协议
  • 八、使用 ARP 协议凭借 MAC 地址通信
  • 九、服务器响应请求
  • 十、断开 TCP 连接
  • 十一、浏览器显示界面
  • 十二、总结

一、前言

在浏览器的地址栏输入一个 URL 后回车,背后到底发生了什么才能使得一个界面完美的展现在我们眼前?

今天讲解的这道题目,由于其涉及大量网络协议,可以非常直观的看出诸位小伙伴对计算机网络体系的整体把握程度,所以自然成为了各大公司的面试常客。

在浏览中输入 URL 并且获取响应的过程,其实就是浏览器和该 URL 对应的服务器的网络通信过程。比如我们输入 www.baidu.com,那么会返回一个百度搜索的界面,这其实就是浏览器和百度服务器之间的网络通信过程。浏览器就是客户端,用于发出请求,而百度的服务器就是服务端,用于接收并响应请求。

下面我们就来详细讲解这个庞大的网络通信过程。

二、解析 URL

不知道有没有同学会混淆域名和 URL 的概念,可以这样理解,URL 就是我们输入的网址,而网址里面含有域名。举个例子:www.baidu.com/veal98 是一个网址,而 www.baidu.com 就是服务器的域名。

URL 各元素的组成如下(当然,下述请求文件的路径名可以省略):

这个 URL 请求的目标服务器上的文件路径就是:

那么首先,浏览器做的第一步就是解析 URL 得到里面的参数,将域名和需要请求的资源分离开来,从而了解需要请求的是哪个服务器,请求的是服务器上什么资源等等。

三、浏览器封装 HTTP 请求报文

URL 进行解析之后,浏览器确定了目标服务器和文件名,接下来就需要根据这些消息封装成一个 HTTP 请求报文发送出去。举个 HTTP 请求报文的例子:

解释一下封装,这是一个贯穿整个计算机网络的概念。就是说发送端在层与层之间传输数据时,每经过一层必定会被打上一个该层所属的首部信息。反之,接收端在层与层之间传输数据时,每经过一层就会把该层对应的首部信息消去。

四、DNS 域名解析获取 IP 地址

封装好 HTTP 请求报文后,在正式还有一项准备工作没有做,那就是获取目标服务器的 IP 地址。

虽然解析得到了域名,理论浏览器已经知道目标服务器是谁了。但是实际上,域名并不是目标服务器真正意义上的地址,互联网上每一台计算机都被全世界唯一 IP 地址标识着,但是 IP 地址并不方便记忆,所以才设计出了域名。

那么就需要解析域名获取目标服务器的 IP 地址。不然空有一个方便记忆的域名咋知道这个请求到底发送到哪里去呢。由域名转换得到 IP 地址就是 DNS 协议做的事情,如下:

1)首先搜索浏览器的 DNS 缓存,缓存中维护着一张域名与 IP 地址的对应表;

2)若没有命中,则继续搜索操作系统的 DNS 缓存;

3)若仍然没有命中,则操作系统将域名发送至本地域名服务器,本地域名服务器查询自己的 DNS 缓存,查找成功则返回结果(注意:主机和本地域名服务器之间的查询方式是递归查询);

4)若本地域名服务器的 DNS 缓存没有命中,则本地域名服务器向上级域名服务器进行查询,通过以下方式进行迭代查询(注意:本地域名服务器和其他域名服务器之间的查询方式是迭代查询,防止根域名服务器压力过大):

  • 首先本地域名服务器向根域名服务器发起请求,根域名服务器是最高层次的,它并不会直接指明这个域名对应的 IP 地址,而是返回顶级域名服务器的地址,也就是说给本地域名服务器指明一条道路,让他去这里寻找答案
  • 本地域名服务器拿到这个顶级域名服务器的地址后,就向其发起请求,获取权限域名服务器的地址
  • 本地域名服务器根据权限域名服务器的地址向其发起请求,最终得到该域名对应的 IP 地址

4)本地域名服务器将得到的 IP 地址返回给操作系统,同时自己将 IP 地址缓存起来

5)操作系统将 IP 地址返回给浏览器,同时自己也将 IP 地址缓存起来

6)至此,浏览器就得到了域名对应的 IP 地址,并将 IP 地址缓存起来

配合下图直观理解:

需要注意的是,DNS 使用的是 UDP 协议,也就是说上面各种请求的转发,都是基于 UDP 这个无连接协议的。

五、建立 TCP 连接

获取到了目标服务器的 IP 地址之后,浏览器就知道我等下请求要发给谁了,这个时候就可以开始发送封装好了的 HTTP 请求报文了,那么既然需要发送请求,必然就需要 TCP 通过三次握手为浏览器和服务器之间建立可靠的连接,保证双方都具有可靠的接收和发送能力。

三次握手过程如下图:

六、浏览器发送请求

TCP 三次握手完成后,浏览器与目标服务器之间就建立了一个可靠的虚拟通道,于是浏览器就可以发送自己的 HTTP 请求了。

需要注意的是,HTTP 请求报文或者响应报文在 TCP 连接通道上进行传输的时候,由于这些报文比较大,为了更容易和准确可靠的传输,TCP 会将 HTTP 报文按序号分割成若干报文段并加上 TCP 首部,分别进行传输。接收方在收到这些报文段后,按照序号以原来的顺序重组 HTTP 报文。

七、负责传输的 IP 协议

实际上,TCP 在三次握手建立连接、四次握手断开连接、以及连接建立过程中的收发数据(TCP 报文段)等各阶段操作时,都是通过 IP 协议进行传输的,IP 协议将这些阶段的数据添加 IP 首部封装成 IP 数据报再进行传输。

IP 数据报的首部存有源 IP 地址和 目标 IP 地址。所谓源 IP 地址 就是发送方的 IP 地址;目标 IP 地址就是通过 DNS 域名解析得到的目标服务器的 IP 地址。

事实上,IP 协议身处的网络层规定的是:数据报要通过怎样的路径(传输路线)才能到达对方计算机,并传送给对方。不理解这句话的详细解释马上就来,继续往下读。

八、使用 ARP 协议凭借 MAC 地址通信

上面说了,IP 协议的作用是把各种数据包传送给对方,而要保证确实传送到对方那里,则需要满足各类条件,其中必要的两个就是 IP 地址 和 MAC 地址。

MAC 地址也是用来唯一标识一个接入互联网的设备的,可能不禁有小伙伴要问,既然网络层已经有了唯一标识的 IP 地址,为啥还需要 MAC 地址?

看下面这幅图,在网络上,通信的双方在同一局域网内的情况是很少见的,通常是需要多台计算机和网络设备的中转才能连接到对方。而在进行中转时,就需要利用下一站中转设备的 MAC 地址来搜索下一个中转目标。

  • 网络层指定了从哪个主机(「源 IP 地址」)发送到哪个主机(「目的 IP 地址」)。源 IP 地址和目标 IP 地址在传输过程中是不会变化的
  • 而数据链路层则是根据 MAC 地址在一个接一个的区间中进行传输的,每个区间内的出发地址即「源 MAC 地址」,每个区间内的目的地址即「目的 MAC 地址」。显然,随着数据的传输,源 MAC 地址和目的 MAC 地址会不断的发生变化

比如上图,网络层告知了 1-2-3 路线,也就是说指明了这几个路由器的 IP 地址。那么数据链路层就会根据这几个 IP 地址对应的 MAC 地址依次找到 1、2、3,并在他们之间传输数据。

这么说吧,举个形象点的例子:我们把数据链路层当成乘坐高铁从苏州到南京,再在南京转乘到北京,再在北京转乘到西藏的旅客,那么网络层就相当于每个车站的工作人员,在数据链路层每次转乘时,网络层为其购买了一张标有下一个 MAC 地址的车票。因此,即使旅客(数据链路层)不知道其最终目的地也没有关系,工作人员(网络层)会给你做出指引。

实际上,网络层做出指引的过程,我们将其称为路由控制,其中又涉及到了路由协议比如 OSPF 等

那么,将 IP 地址转化为 MAC 地址,从而在数据链路层精确的传输数据的协议就是 ARP 协议。

ARP 是借助 ARP 请求与 ARP 响应两种类型的包确定 MAC 地址的。并且每个主机都有一个 ARP 高速缓存,里面有本局域网上的各主机和路由器的 IP 地址到 MAC 地址的映射表。

如下图所示,假定主机 A 向同一链路上的主机 B 发送 IP 数据报,已知主机 A 和主机 B 的 IP 地址,它们互不知道对方的 MAC 地址:

1)首先,主机 A 为了获得主机 B 的 MAC 地址,它会先去查询自己的 ARP 高速缓存中有没有主机 B 的相关记录;

2)如果主机 A 的 ARP 高速缓存中没有主机 B 的 IP 地址到 MAC 地址的映射,主机 A 就会通过广播的方式发送 ARP 请求包(该包携带自己的 IP 地址 和 MAC 地址 以及 目标主机的 IP 地址),表明自己想要获得主机 B 的 MAC 地址;

2) 由于广播请求可以被同一个链路上的所有主机或路由器接收,因此如果这条链路上某个主机或路由的 IP 地址与这个 ARP 请求包中包含的目标主机的 IP 地址相同,那么这个节点就将自己的 MAC 地址塞入 ARP 响应包中返回给主机 A;

当然,ARP 响应包是以单播的形式进行发送的,毕竟 ARP 请求包中已经包含了主机 A 的 IP 地址,所以主机 B 非常清楚这个响应包应该发送给谁。

大部分网络协议在设计的时候,都是保持极度克制的,不需要的交互就砍掉,能合并的信息就合并,能不用广播就用单播,以此让带宽变得更多让网络变得更快。

3)主机 A 在收到主机 B 发过来的 ARP 响应包后,向其 ARP 高速缓存中写入主机 B 的 IP 地址到 MAC 地址的映射。

当然,缓存是有一定期限的,超过这个期限,缓存的内容将被清空。这也使得即使 MAC 地址和 IP 地址的映射关系发生了变化,也依然能够正确的将数据包发送给目标地址。

九、服务器响应请求

浏览器的 HTTP 请求报文通过 TCP 三次握手建立的连接通道被切分成若干报文段分别发送给服务器,服务器在收到这些报文段后,按照序号以原来的顺序重组 HTTP 请求报文。然后处理并返回一个 HTTP 响应。当然,HTTP 响应报文也要经过和 HTTP 请求报文一样的过程。

看下方这个图回顾一下(图片来源《图解 HTTP》):

十、断开 TCP 连接

浏览器和服务器都不再需要发送数据后,四次挥手断开 TCP 连接

十一、浏览器显示界面

浏览器接收到服务器返回的数据包,根据浏览器的渲染机制对相应的数据进行渲染

十二、总结

屏蔽掉底层细节,笼统的总结一下上述过程:

应用层:

  • 浏览器封装 HTTP 请求报文
  • DNS 解析域名获得目标服务器地址

传输层:

  • 建立连接
  • 把应用层传过来的 HTTP 请求报文进行分割,并在各个报文上打上标记序号及端口号转发给网络层

网络层:

  • 利用 ARP 协议根据 IP 地址获取作为通信目的地的 MAC 地址后转发给链路层

服务端在链路层收到数据,按序往上层发送,一直到应用层接收到浏览器发送来的 HTTP 请求报文,然后处理该请求并返回 HTTP 响应报文,浏览器接收到响应报文之后解析渲染界面。最后 TCP 断开连接。

以上就是解析在浏览器地址栏输入一个URL后发生了什么的详细内容,更多关于在浏览器地址栏输入一个URL的资料请关注我们其它相关文章!

(0)

相关推荐

  • 使用JavaScript解析URL的方法示例

    前言 在 Web 开发中,有许多情况需要解析 URL,这篇主要学习如何使用 URL 对象实现这一点.下面话不多说了,来一起看看详细的介绍吧 开始 创建一个以下内容的 HTML 文件,并在浏览器中打开. <html> <head> <title>JavaScript URL parsing</title> </head> <body> <script> // 激动人心的代码即将写在这里 </script> <

  • php解析url并得到url中的参数及获取url参数的四种方式

    下面一段代码是php解析url并得到url中的参数,代码如下所示: <?php $url = 'http://www.baidu.com/index.php?m=content&c=index&a=lists&catid=6&area=0&author=0&h=0&region=0&s=1&page=1'; $arr = parse_url($url); var_dump($arr); $arr_query = convertU

  • php使用parse_url和parse_str解析URL

    PHP中有两个方法可以用来解析URL,分别是parse_url和parse_str. parse_url 解析 URL,返回其组成部分 mixed parse_url ( string $url [, int $component = -1 ] ) 本函数解析一个 URL 并返回一个关联数组,包含在 URL 中出现的各种组成部分. 本函数不是用来验证给定 URL 的合法性的,只是将其分解为下面列出的部分.不完整的 URL 也被接受,parse_url() 会尝试尽量正确地将其解析. 参数 url

  • JS解析url查询参数的简单代码

    废话不多说了,直接给大家贴代码了,具体代码如下所述: var path = 'www.u.com/home?id=2&type=0&dtype=-1'; function parseUrl(url){ var result = []; var query = url.split("?")[1]; var queryArr = query.split("&"); queryArr.forEach(function(item){ var obj

  • 解析在浏览器地址栏输入一个URL后发生了什么

    目录 一.前言 二.解析 URL 三.浏览器封装 HTTP 请求报文 四.DNS 域名解析获取 IP 地址 五.建立 TCP 连接 六.浏览器发送请求 七.负责传输的 IP 协议 八.使用 ARP 协议凭借 MAC 地址通信 九.服务器响应请求 十.断开 TCP 连接 十一.浏览器显示界面 十二.总结 一.前言 在浏览器的地址栏输入一个 URL 后回车,背后到底发生了什么才能使得一个界面完美的展现在我们眼前? 今天讲解的这道题目,由于其涉及大量网络协议,可以非常直观的看出诸位小伙伴对计算机网络体

  • 用vbs 实现从剪贴板中抓取一个 URL 然后在浏览器中打开该 Web 站点

    问: 嗨,Scripting Guy!我如何从剪贴板中抓取一个 URL 然后在浏览器中打开该 Web 站点? -- CL 答: 您好,CL.这是很有趣的问题,或者我们应当说,这是两个很有趣的问题.因为您实际上问了两个问题.第一个问题很简单:我可以使用脚本打开特定的 Web 站点吗?您大概已经知道答案了,我可以大声地回答您,可以!下面是一个示例脚本,它将"脚本中心"的 URL 存储在一个名为 strURL 的变量中.然后,此脚本会创建 WSH Shell 对象的一个实例,并使用 Run 

  • 返回上一个url并刷新界面的js代码

    JS 重载页面,本地刷新,返回上一页 <a href="javascript:history.go(-1)" rel="external nofollow" >返回上一页</a> <a href="javascript:location.reload()" rel="external nofollow" >重载页面,本地刷新</a> <a href="javasc

  • python解析Chrome浏览器历史浏览记录和收藏夹数据

    目录 前言 (一)查询chrome数据缓存地址 (二)提取收藏夹数据 1.文件路径 2.解析代码 (三)查看浏览历史数据 1.文件路径 2.解析代码 (四)完整代码&测试代码 总结 前言 常使用chrome浏览器作为自己的默认浏览器,也喜欢使用浏览器来收藏自己的喜欢的有用的链接,自己也做了一个记录笔记的小脚本,想扩展收录chrome浏览器收藏夹的内容,,下面,,使用python提取chrome浏览器的历史记录,以及收藏夹. (一)查询chrome数据缓存地址 1.打开 chrome浏览器,输入

  • 使用Python解析Chrome浏览器书签的示例

    Chrome 浏览器的书签如果可以导出,并转换为我们需要的格式时,我们就可以编写各种插件来配合书签的使用. 答案显然是可以的,接下来我们以 Python 为例写一个遍历打印书签的例子 书签地址 先来说下获取书签的方法 Chrome 浏览器的书签存放位置在各个平台的区别 Mac ~/Library/Application Support/Google/Chrome/Default/Bookmarks Linux ~/.config/google-chrome/Default/Bookmarks W

  • Springboot如何去掉URL后面的jsessionid

    目录 如何去掉URL后面的jsessionid url中有Jsessionid生成的原因 解决方式一 解决方式二 Java关于jsessionid和URL 对SEO的冲击 安全问题 解决之道 如何去掉URL后面的jsessionid url中有Jsessionid生成的原因 jsessionid是标明session的id,它存在于cookie中,一般情况不会出现在url中,服务器会从客户端的cookie中取出来,但是如果客户端禁用了cookie的话,就要重写url了,显式的将jsessionid

  • java 输入一个数字,反转输出这个数字的值(实现方法)

    如下所示: package 第四天; import java.util.Scanner; public class 数字反转 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入一个整数:"); int num=sc.nextInt(); int result=0;//存反转的数字 while(true) { int n=num%10

  • JS获取浏览器地址栏的多个参数值的任意值实例代码

    下面通过一段代码给大家介绍js获取浏览器地址栏的多个参数值的任意值,具体代码如下所示: getParamValue("id"); //http://localhost:2426/TransactionNotes.aspx?id=100 //返回值是100: // 根据参数名称获取参数值 function getParamValue(name) { var paramsArray = getUrlParams(); if (paramsArray != null) { for (var

  • Java如何实现通过键盘输入一个数组

    目录 如何通过键盘输入一个数组 第一种方法:(不限制输入数组的长度) 第二种方法:(限制输入的个数) 不限制从键盘输入一个数组 下面用二分查找举例 如何通过键盘输入一个数组 有时候在编写Jave的时候需要键盘输入一个数组,本小白也是看了几篇博客后才知道了如何在自己的程序中进行键盘输入,直接上代码: 第一种方法:(不限制输入数组的长度) System.out.println("请输入几个数并用逗号隔开:"); Scanner sc = new Scanner(System.in); St

  • 前端面试之输入npm run后执行原理

    目录 引言 引言 在前端开发的工作当中,使用 npm run dev 的命令启动本地开发环境,是再正常不过的事了.那么,当输入完类似 npm run xxx 的命令后,究竟是如何触发各种构建工具的构建命令以及启动 Node 服务等功能的呢? 首先我们知道,Node 作为 JavaScript 的运行时,可以把 .js 文件当做脚本来运行,像这种: node index.js 当我们使用 npm 来管理项目(或者 yarn)时,会在根目录下生成一个 package.json 文件,其中的 scri

随机推荐