草庐IT

在浏览器上输入一个网址后,发生了什么?/HTTP的工作流程/DNS域名解析过程

欢喜躲在眉梢里 2023-09-06 原文

这是一个比较常见且经典的问题,我们或者用户通过浏览器访问某个网站,比如用户点击URL为http://www.sxtyu.com/index.html的链接或者访问www.baidu.com,敲回车之后,浏览器的背后发生了什么?

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

目录

1、浏览器先分析超链接中的URL

 2、浏览器向DNS请求解析请求解析IP地址

DNS域名解析IP地址的过程为:

3、DNS将解析出的IP地址返回浏览器

4、浏览器与服务器建立TCP连接(80端口,三次握手)

 5、浏览器请求文档(GET/index.html)

6、服务器给出响应,将文档index.html发送给浏览器,浏览器进行解封装。

7、浏览器显示index.html中的内容(渲染页面)

8、释放TCP连接(四次挥手

从封装的角度来讲,浏览器和web服务器执行以下动作:(简单流程)

1、浏览器先分析超链接中的URL:分析域名是否规范

2、浏览器向DNS请求解析请求解析http://www.sxtyu.com/index.html中的ip地址

3、DNS将解析出的ip地址返回浏览器

4、浏览器与服务器建立TCP连接(80端口,三次握手)

5、浏览器请求文档(GET/index.html)

6、服务器给出响应,将文档index.html发送给浏览器,浏览器进行解封装。

7、浏览器显示index.html中的内容(渲染页面)

8、释放TCP连接(四次挥手)

新版是这个流程,老版是先7后8。

1、浏览器先分析超链接中的URL

首先,URL是由协议、主机和端口(默认为80)以及文件名三部门构成。如:

http://www.sxtyu.com:80/news/index.html

协议                    主机:端口(80)/

我们可以这样理解:URL就是我们输入的网址,而网址里面含有域名。比如www.baidu.com/veal98 是一个网址,而 www.baidu.com 就是服务器的域名。

URL的各元素组成为:(其中的请求文件的路径可以省略)

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

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

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

 对于这个封装,其中涉及到计算机网络中的知识。就是说发送端在层与层之间传输数据的时候,每经过一层必定会被打上一个该层所属的首部信息。反之,接收端在层与层之间传输数据的时候,没经过一层就会把该层对应的首部消息消除。

 2、浏览器向DNS请求解析请求解析IP地址

封装好HTTP请求报文之后,就需要获取目标服务器的ip地址(ip包里面有ip地址),虽然解析得到了域名,按理浏览器应该已经知道了目标服务器是谁了。但是实际上,域名并不是目标服务器真正意义上的地址,互联网上每一台计算机都被全世界唯一IP地址标识着,但是IP地址并不方便记忆,所以才设计出了域名。但是虽然域名容易被用户所接受和使用,但是计算机只能识别纯数字构成的IP地址,不能直接读取域名。所以如果只是知道域名也不知道这个请求会被发送到哪里去。那么就需要解析域名获取目标服务器的IP地址。

此时的浏览器就会向DNS请求解析请求解析http://www.sxtyu.com/index.html中的ip地址。

DNS域名解析IP地址的过程为:

1.客户端首先查看浏览器缓存,看有没有该域名对应的IP地址

2.如果没有的话,查看本地host文件,看有没有该域名对应的IP地址

3.如果没有的话,客户端向本地域名服务器进行递归查询,查询该域名对应的IP地址

4.如果还是没有的话,本地域名服务器向根域名服务器进行迭代查询,根域名服务器通常是把自己知道的顶级域名服务器的IP地址告诉本地域名服务器

5.本地域名服务器再向顶级域名服务器查询,顶级域名服务器要么给出所要查询的IP地址,要么告诉本地服务器下一步应该向哪一个权限域名服务器进行查询

6.本地域名服务器向权限域名服务器进行查询,然后得到了所要解析的IP地址

7.本地域名服务器将该域名和对应的IP地址写入自身缓存,然后将解析的IP地址返回给客户端。

1、首先本地电脑会检查浏览器DNS缓存中有没有这个域名对应的解析过的IP地址。

如果缓存的中有,这个解析过程就结束。缓存中维护着一张域名与 IP 地址的对应表。浏览器缓存域名也是有限制的,不仅浏览器缓存大小有限制,而且缓存的时间也有限制,通常情况下,缓存时间为几分钟到几个小时或者更长。域名被缓存的时间限制可以通过TTL属性来设置,这个缓存时间太长、太短都不太好。如果时间太长,一旦域名被解析到的ip发生变化,就会导致客户端缓存的域名无法解析到变化后的ip地址,导致该域名不能正常解析,这段时间内会有一部分用户无法访问网站。如果设置时间太短,会导致用户每次访问网站都需要重新解析一次域名,都会影响到用户的使用。

2、如果浏览器缓存中没有数据,浏览器会查找hosts文件(操作系统缓存中:hosts文件)看有没有该域名对应的IP地址。

其中的操作系统也有一个域名解析的过程,在Linux中可以通过/etc/hosts文件中来设置,Windows中可以通过配置C:\Windows\System32\drivers\etc\hosts文件来设置,用户可以将任何域名解析到任何能够访问到的ip地址。

如:我们可以在测试的时候将一个域名解析到一台测试服务器上,这样不用修改任何代码就能测试到单独服务器上的代码的业务逻辑是否正确。正是因为有这种本地DNS解析的规程,所以就可能有黑客通过修改用户的域名来把特定的域名解析到他指定的ip地址上,导致域名被劫持。

3、如果本地缓存文件中也没有的话,就需要使用到网络配置中的“DNS服务器地址”。

操作系统会把这个域名发送给本地DNS服务器。每个完整的内网通常都会配置本地DNS服务器,例如用户是在学校或者单位接入互联网,那么用户的本地DNS服务器肯定是在学校或者工作单位里面。它们一般都会缓存域名解析结果,当然缓存时间是受到域名的失效时间控制的。后面的DNS迭代和递归也是由本地DNS服务器负责的。

Windows的配置在:控制面板-网络共享中心-更改适配器-选择目标适配器右键选择属性-Internet协议版本4(TCP/IPv4)-》配置DNS地址。

Linux中的配置在:/etc/resolv.conf

[root@nginx-kafka01 etc]# cat /etc/resolv.conf
# Generated by NetworkManager
nameserver 114.114.114.114
nameserver 192.168.2.1

本地域名服务器记录的解析如果有就会直接返回,如果没有解析,就会去根域名服务器(www顶级域.baidu:二级域.com)找全球13台,依次迭代查询得到最后的ip解析地址 ,通过迭代去查询的。(注意:主机和本地域名服务器之间的查询方式是递归查询)

4、如果DNS服务器中还是没有,本地域名服务器向根域名服务器进行迭代查询

(注意:本地域名服务器和其他域名服务器之间的查询方式是迭代查询,防止根域名服务器压力过大)

通过以下方式进行迭代查询:

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

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

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

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

递归查询和迭代查询的区别:

DNS客户端和本地名称服务器是递归查询,而本地名称服务器和其他名称服务器之间是迭代查询。

DNS递归名称解析:

在DNS递归解析中,当所配置的本地名称服务器解析不了时,后面的查询工作是由本地名称服务器替代DNS客户端进行的(以“本地名称服务器”为中心),只需要本地名称服务器向DNS客户端返回最终的查询结果即可。

DNS迭代名称解析(查询):迭代查询的所有查询工作全部是DNS客户端自己进行(以“DNS客户端”自己为中心),在其中一条件满足之后就会采用迭代名称解析方式。

  • 在查询本地名称服务器时,如果客户端的请求报文中没有申请使用递归查询,即在DNS请求报头部的RD字段没有置1。相当于说“你都没有主动要求我为你进行递归查询,我当然不会为你工作了”。
  • 客户端在DNS请求报文中申请使用的是递归查询(也就是RD字段置1了),但在所配置的本地名称服务器上是禁用递归查询(DNS服务器一般默认支持递归查询的),即在应答DNS报文头部的RA字段置0。

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

3、DNS将解析出的IP地址返回浏览器

4、浏览器与服务器建立TCP连接(80端口,三次握手)

三次握手的流程:

第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

 5、浏览器请求文档(GET/index.html)

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

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

HTTP中的请求报文:

请求报文:客户端(浏览器)向web服务器发送的请求报文。报文的所有字段都是ASCII码。

请求报文中可以携带数据,也可以不携带数据。 请求报文由请求行、请求头部、空行和请求包体 4 个部分组成。

首部行:用来说明浏览器、服务器或报文主体是一些信息。

首部字段:请求报文里。请求的时候需要携带数据告诉服务器自己需要访问的东西。携带的数据是通过头部字段(header)去访问。

请求报文里面的字段:

请求报文里的字段:提问 requests: 请求报文

  • ①Host:表示访问的主机。表示访问的那个网址---》URL(通过域名dns或者ip地址)
  • ②connection:close或者keepalive 表示当前是连接还是断开的状态。
  • ③user-agent :表示使用的是什么用户代理---》浏览器(本质上使用的是什么浏览器):请求字段,用来描述发起请求的客户端,比如是Chrome、Mozilla、Safari,或者是spider。
  • ④Accept-language.cn :客户端可接受的自然语言。
  • ⑤Accept-encode.cn:客户端可接受的编码压缩格式;接收的编码、接收的类型的文件(表示的是压缩)
  • ⑥cookie:存储于客户端扩展字段,向同一域名的服务端发送属于该域的cookie;

请求行:方法、URL、版本

  • 常见的方法为:GET、POST、PUT、DELETE等
  • 常见的版本为:HTTP1.0、HTTP1.1、HTTP2.0等

6、服务器给出响应,将文档index.html发送给浏览器,浏览器进行解封装。

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

HTTP的响应报文:response响应报文,即从Web服务器到客户机(浏览器)的应答。报文的所有字段都是ASCII码。

HTTP 响应报文由状态行、响应头部、空行 和 响应包体 4 个部分组成

reposes里面的状态码:重要

状态行:状态码(列举常见的)

  • 200 :  响应成功 
  • 301:永久重定向,请求资源的url已永久更改,在响应中给出了新的url。

  • 302:临时重定向。

  • 304:not modify(未改变,和缓存里面的是一样的)

  • 404:not found ,网页不存在。

  • 502:bad gateway (网关故障),但是后端的real server挂了。

  • 500:内部服务器错误。(服务器崩溃了)

响应头部:响应字段

Date:日期,通用字段,但通常出现在响应头里,表示 HTTP 报文创建的时间,客户端可以使用这个时间再搭配其他字段决定缓存策略

Server:Server 响应报头域包含了服务器用来处理请求的软件信息及其版本。它和 User-Agent 请求报头域是相对应的,前者发送服务器端软件的信息,后者发送客户端软件(浏览器)和操作系统的信息。

cache-control: max-age=30

content-type:传递过来的类型。

7、浏览器显示index.html中的内容(渲染页面)

浏览器接收到服务器返回的数据包,根据浏览器的渲染机制对相应的数据进行渲染。渲染就是将响应报文里的html文件+图片+视频等展示出来,看到效果。浏览器支持HTML语言,支持http,播放器等功能。

8、释放TCP连接(四次挥手)

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

四次挥手详解

有关在浏览器上输入一个网址后,发生了什么?/HTTP的工作流程/DNS域名解析过程的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  5. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  6. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  7. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  8. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  9. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  10. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

随机推荐