【2.0】Web服务器的本质
【一】从浏览器输入一个地址到看到页面信息的过程
【1】在浏览器中输入网址(URL)
- 用户在浏览器的地址栏中输入目标网址(例如:https://www.example.com),并按下回车键。
【2】DNS解析
- 浏览器会先检查是否有缓存过该域名的IP地址,如果有缓存则直接使用,否则浏览器会向本机的DNS缓存查找域名对应的IP地址。
- 如果找不到,则浏览器会向递归解析服务器发送DNS查询请求。
- 这个过程中可能包括本地Hosts文件的解析、本地DNS缓存的查询以及顶级域名服务器(Root DNS Server),依次通过多级的DNS服务器逐步解析出目标域名的IP地址。
例如:
- 用户输入的URL为https://www.example.com,经过DNS解析后得到IP地址为192.0.2.123。
【3】建立TCP连接
-
浏览器使用获取到的IP地址和默认的端口号(通常是80)与目标服务器建立TCP连接。
-
这个过程涉及到TCP/IP的三次握手,确保客户端和服务器之间建立稳定可靠的连接。
【4】发送HTTP请求
- 一旦TCP连接建立成功,浏览器会发送一个HTTP请求给目标服务器。
- 该请求会包含一些重要信息,例如请求方法(GET、POST等)、请求头(User-Agent、Cookies等)和请求体(如果有数据需要上传)。
例如:
- 浏览器发送一个GET请求给服务器,请求的资源路径为/。
【5】服务器处理请求
-
目标服务器接收到浏览器发送的HTTP请求后,会根据请求的内容进行相应的处理。
-
这个过程会涉及到后端服务的运行,例如使用Nginx作为反向代理服务器将请求转发给后端Web框架(如Django、Flask等)。
【6】服务器发送HTTP响应
-
服务器处理完请求后,会生成一个HTTP响应,该响应包括状态码、响应头和响应体。
-
状态码表示服务器对请求的处理结果,响应头包含了一些元信息,而响应体包含了请求的实际内容。服务器将该HTTP响应发送回客户端浏览器。
【7】接收并渲染页面
-
浏览器接收到服务器发送的HTTP响应后,会根据响应的内容进行解析和渲染。
-
浏览器会根据Content-Type等响应头信息确定如何展示内容,如果内容是HTML页面,则浏览器会解析HTML标记、加载外部样式表和脚本文件,并将页面渲染出来。
【8】断开TCP连接
- 页面渲染完成后,如果没有keep-alive机制或者WebSocket等长连接技术,浏览器会发送一个关闭TCP连接的请求给服务器,进而两者断开连接。
- 需要注意的是,上述过程中还涉及到重定向、HTTPS安全连接以及其他一些特殊情况的处理,但基本的流程如上所述。
- 此外,还有一些细节可以进一步扩展和讨论,例如HTTP/2、HTTP/3等协议的特点及优化。
【二】从浏览器输入一个地址到看到页面信息的详细过程
【1】总览
-
浏览器先分析超链接中的URL:分析域名是否规范
-
浏览器向DNS请求解析请求解析 https://www.example.com/index.html 中的ip地址
-
DNS将解析出的ip地址返回浏览器
-
浏览器与服务器建立TCP连接(80端口,三次握手)
-
服务器接收到浏览器请求文档(GET/index.html)进行处理
-
服务器给出响应,将文档index.html发送给浏览器,浏览器进行解封装。
-
浏览器渲染 index.html 中的内容(渲染页面)
-
释放TCP连接(四次挥手)
【2】浏览器先分析超链接中的URL
(1)输入的浏览器网址分析
-
首先,URL是由协议、主机和端口(默认为80)以及文件名三部门构成。
-
如:https://www.example.com:80/index.html
- 协议(https://www.example.com):端口(80)/详细地址
-
我们可以理解为 URL 就是我们在浏览器中输入的地址,而输入的URL中就携带者域名
- 比如 https://www.baidu.com 访问百度官网
- 其中 www.baidu.com 就是百度服务器的域名
(2)简析URL的组成
- URL 的元素组成也和上述大致相似
- 其中 访问协议 和 域名是必须的,目录名和文件名可以忽略
- 相应的 URL 请求对应在服务器上的文件路径如下
(3)分析域名是否规范
-
首先,浏览器做的第一步就是会解析URL得到里面的参数,分析域名是否规范,并将域名和需要的请求的资源分离开来,从而了解需要请求的是哪个服务器,请求的是服务器上的什么资源等等。
-
浏览器对URL进行解析之后,浏览器确定了目标服务器和文件名,接下来就是需要根据这些消息封装成一个HTTP请求报文发送出去。
-
HTTP请求报文的例子为:
- 对于这个封装,其中涉及到计算机网络中的知识。
- 就是说发送端在层与层之间传输数据的时候,每经过一层必定会被打上一个该层所属的首部信息。
- 反之,接收端在层与层之间传输数据的时候,没经过一层就会把该层对应的首部消息消除。
【2】DNS解析
(1)DNS 解析简解
- 封装好HTTP请求报文之后,就需要获取目标服务器的ip地址(ip包里面有ip地址),虽然解析得到了域名,按理浏览器应该已经知道了目标服务器是谁了。
- 但是实际上,域名并不是目标服务器真正意义上的地址,互联网上每一台计算机都被全世界唯一IP地址标识着,但是IP地址并不方便记忆,所以才设计出了域名。
- 但是虽然域名容易被用户所接受和使用,但是计算机只能识别纯数字构成的IP地址,不能直接读取域名。
- 所以如果只是知道域名也不知道这个请求会被发送到哪里去。
- 那么就需要解析域名获取目标服务器的IP地址。
- 此时的浏览器就会向DNS请求解析请求解析 https://www.example.com:80/index.html 中的 IP地址
举个形象的例子
- 我们经常通过
ping www.baidu.com
来检验我们的服务器是否能连通外网- 其实在
ping www.baidu.com
过程中,就发生了 DNS 解析操作C:\Users\Administrator>ping www.baidu.com 正在 Ping www.a.shifen.com [180.101.50.188] 具有 32 字节的数据: 来自 180.101.50.188 的回复: 字节=32 时间=10ms TTL=52 180.101.50.188 的 Ping 统计信息: 数据包: 已发送 = 1,已接收 = 1,丢失 = 0 (0% 丢失), 往返行程的估计时间(以毫秒为单位): 最短 = 10ms,最长 = 10ms,平均 = 10ms
- 我们可以看到,百度的 IP 地址就是
180.101.50.188
- 我们通过 在浏览器地址栏输入
http://180.101.50.188/
- 等价于,我们在浏览器地址栏输入
https://www.baidu.com/
(2)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地址。
- 在Linux中可以通过
- 我们可以在测试的时候将一个域名解析到一台测试服务器上,这样不用修改任何代码就能测试到单独服务器上的代码的业务逻辑是否正确。
- 正是因为有这种本地DNS解析的规程,所以就可能有黑客通过修改用户的域名来把特定的域名解析到他指定的ip地址上,导致域名被劫持。
3、如果本地缓存文件中也没有的话,就需要使用到网络配置中的“DNS服务器地址”。
- 操作系统会把这个域名发送给本地DNS服务器。
- 每个完整的内网通常都会配置本地DNS服务器
- 例如用户是在学校或者单位接入互联网,那么用户的本地DNS服务器肯定是在学校或者工作单位里面。
- 它们一般都会缓存域名解析结果,当然缓存时间是受到域名的失效时间控制的。
- 后面的DNS迭代和递归也是由本地DNS服务器负责的。
- 每个完整的内网通常都会配置本地DNS服务器
- Windows的配置在:
- 控制面板
- 网络共享中心
- 更改适配器
- 选择目标适配器右键选择属性
- Internet协议版本4(TCP/IPv4)
- 配置DNS地址。
- Linux中的配置在:/etc/resolv.conf
[root@VM-8-11-opencloudos ~]# cat /etc/resolv.conf
# Generated by NetworkManager
nameserver 183.60.83.19
nameserver 183.60.82.98
- 本地域名服务器记录的解析如果有就会直接返回,如果没有解析,就会去根域名服务器(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)去访问。
-
请求报文里的字段
-
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 连接。
四次握手指断开TCP协议连接时客户端和服务器之间的交互过程
- 客户端向服务器发送一个FIN(结束)报文
- 表示要关闭连接。
- 服务器收到FIN报文后向客户端回送一个ACK报文
- 表示已经收到客户端的请求。
- 如果服务器还有数据需要发送给客户端
- 则继续发送直到数据全部发送完毕。
- 服务器发送一个FIN报文,表示数据已经全部发送完毕
- 可以关闭连接。
- 客户端收到FIN报文后向服务器发送一个ACK报文,表示确认收到关闭请求。
- 此时客户端需要进入TIME-WAIT状态,等待两倍的报文最大生存时间,以保证数据已经被全部传输完毕。
- 如果服务器没有收到来自客户端的ACK报文,则会重传FIN报文。
本文来自博客园,作者:Chimengmeng,转载请注明原文链接:https://www.cnblogs.com/dream-ze/p/18036064