欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

输入url到页面加载完成发生了什么谈跨域、缓存、DNS、http与https(版本,状态码,请求头)以及TCP/IP(三次握手四次挥手)

程序员文章站 2022-03-21 13:13:29
输入URL到页面加载完成发生了什么?这是一道非常经典的面试。这道题涉及的知识面很广,每一方面都能追得很深的细问,下面主要讲前端方面涵盖的知识点,想要更深的研究的小伙伴可以自行去了解。浏览器输入URL按回车检查有没有缓存,有缓存(http缓存)则返回200(form cache),否则继续DNS解析URL对应的IP根据IP建立起TCP协议(三次握手)客户端发起http请求服务端处理请求,返回响应资源浏览器接收响应资源(图片、文本、音频、视频等超文本数据);就html而言,浏览器解析构建DOM树...

输入URL到页面加载完成发生了什么?这是一道非常经典的面试。这道题涉及的知识面很广,每一方面都能追得很深的细问,下面主要讲前端方面涵盖的知识点,想要更深的研究的小伙伴可以自行去了解。

  1. 浏览器输入URL按回车
  2. 检查有没有缓存,有缓存(http缓存)则返回200(form cache),否则继续
  3. DNS解析URL对应的IP
  4. 根据IP建立起TCP协议(三次握手)
  5. 客户端发起http请求
  6. 服务端处理请求,返回响应资源
  7. 浏览器接收响应资源(图片、文本、音频、视频等超文本数据);就html而言,浏览器解析构建DOM树,CSS树渲染页面
  8. 关闭TCP连接(四次握手)

一、URL

URL包括协议名、域名和端口号。其中http的默认端口号(一般会隐藏)为80,https的默认端口号为443。在这里可能会细问跨域,同源策略。协议,端口,域名 都相同时,则为同源,否则是跨域;html的script标签,css,img标签,iframe标签,可以请求第三方的资源(不受同源策略影响)

常见的解决跨域的方式有:

1. JSONP(动态创建script标签)
原理:通过script标签不受同源策略影响的特点,使用 script 跨域请求一段字符串,来执行一个定义好的函数,将请求的数据作为参数回传。
JQuery使用jsonp:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>JSONP 实例</title>
    <script src="http://cdn.static.runoob.com/libs/jquery/1.8.3/jquery.js"></script>    
</head>
<body>
<div id="divCustomers"></div>
<script>
$.getJSON("http://localhost/cors?jsoncallback=?", function(data) {
    var html = '<ul>';
        for(var i = 0; i < data.length; i++){
        html += '<li>' + data[i] + '</li>';
        }
        html += '</ul>';
        $('#divCustomers').html(html); 
});
</script>
</body>
</html>
特点:
 - 只支持get,不支持post
 - 调用失败的时候没有对应的HTTP状态码
 - 安全性不好

2. CORS策略:自定义http首部信息,一般服务器设置Access-Control-Allow-Origin(允许哪些域名访问)就可以实现跨域;前端改动的比较少,主要需要服务端支持该协议。讲到Access-Control-Allow-Origin的同时,也会用到Access-Control-Allow-Credentials:true(允许客户端发送cookie)同时客户端需要设置xhr.withCredentials = true。

cookie设置小结
要想通过客户端发送cookie给服务器端,必须有服务器端支持。

	Access-Control-Allow-Credentials必须为true且只能为true
	Access-Control-Allow-Origin必须指定且不能为'*'
	客户端需要指定xhr.withCredentials = true;
	需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。

cors包含简单请求和非简单请求两种

  1. 简单请求
    条件:
    1. 请求方法为 HEAD GET POST 三种之一;
    2. HTTP请求头信息不超出以下几种字段:
    Accept
    Accept-Language
    Content-Language
    Last-Event-ID
    Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
    请求过程:
    1. 浏览器直接发出cors请求,自动在头信息中增加Origin字段,如 Origin: http://m.siky.top
    2. 服务端根据Origin字段拿到请求源
      如果请求源在许可范围,返回的请求头中就会包含 Access-Control-Allow-Origin 字段
      如果请求源不在许可范围,服务器正常返回http响应
    3. 浏览器收到响应,判断是否有 Access-Control-Allow-Origin 字段
      若有则知道跨域请求成功,正常返回数据
      若无则跟普通跨域请求一样,报错 No ‘Access-Control-Allow-Origin’ ,无返回数据
    4. 服务端返回浏览器端的响应头:
      Access-Control-Allow-Origin 允许跨域的Origin列表
      Access-Control-Allow-Methods 允许跨域的方法列表(GET、POST等)
      Access-Control-Allow-Headers 允许跨域的Header列表
      Access-Control-Expose-Headers 允许暴露给JavaScript代码的Header列表
      Access-Control-Max-Age 最大的浏览器缓存时间,单位为s

2.非简单请求:非简单请求,会在正式通信之前,通过 OPTIONS 请求方法发送一次"预检"请求。

服务器代理:webpack的proxy代理和服务器的nginx代理
关于这个nginx反向代理服务器的相关配置可以去了解一下,nginx反向代理+负载均衡+动静态代理服务器

websocket全双工通信,客户端,服务端这两端都可以主动向对方建立连接,一旦连接建立起来,就可以真正的平等的进行数据交流。这个协议不受http协议的影响,但也需要服务器支持此协议。详情可见:WebSocket 教程 - 阮一峰的网络日志

二、缓存

就浏览器而言,一般缓存我们分为四类,按浏览器读取优先级顺序依次为:Memory Cache、Service Worker Cache、HTTP Cache、Push Cache。而这里主要讲的就是 HTTP Cache ,其他有兴趣可以自行搜索。

http是开发中应用最多的缓存,其中包括强缓存和协商缓存
强缓存:直接从本地副本比对读取,不去请求服务器,返回的状态码是 200。
协商缓存:会去服务器比对,若没改变才直接读取本地缓存,返回的状态码是 304。

强缓存主要包括 expires、pragrma 和 cache-control

  1. expires:
    HTTP1.0中定义的缓存字段,
    请求资源时,服务器返回的响应头Response Headers中增加了expires字段表示资源过期的时间戳,如:
 expires: Thu, 03 Jan 2019 11:43:04 GMT
    当客户端再去请求时,就会用客户端的时间与该时间戳进行对比,若小于该时间戳则用缓存资源,否则进行http请求。
     缺点:
		1. 客户端时间与服务器时间有偏差
		2. 客户端的时间(也就是浏览器的系统时间)是可以通过人为进行修改的。
  1. cache-control:
    HTTP1.1 中定义的字段,可解决 expires 的缺点,优先级大于 expires
cache-control: public, max-age=3600, s-maxage=3600
	(1) max-age / s-maxage
	值为数字,表示缓存在多少秒之后失效,如果未失效则使用缓存,返回200 from cache,若失效了想服务器请求资源,返回200 ok
	浏览器中都起作用,优先级 s-maxage 大于 max-age
	代理服务器中 s-maxage 起作用
	可以通过在 Request Header 中设置 max-age=0 来表示资源过期,进而直接向服务器请求资源
	(2) public / private
	public 表示该资源可被客户端和代理服务器缓存
	private 表示该资源只能被客户端缓存
	默认值为 private ,当未设置 private 且设置了 s-maxage 的时候,表示允许代理服务器缓存,相当于 public
	(3) no-cache / no-store
	no-cache 表示不询问浏览器缓存情况,而是向服务器验证当前资源是否需要更新,是直接使用了协商缓存,若无更新则使用缓存,返回304,否则200 ok
	no-store 则表示不使用缓存策略,直接向服务器请求最新资源
	优先级最高,使用 no-cache / no-store 时,不考虑 max-age 和 s-maxage
  1. pragma:
 pragma: no-cache
值有no-cache/no-store,意思和cache-controll的一样,三者同时出现时的优先级为:pragma->cache-controll->expires

协商缓存主要包括last-modifiedEtag

  1. last-modified
    响应头中增加字段 last-modified ,记录资源最后修改时间,如
last-modified: Fri, 16 Jul 2021 06:22:32 GMT
	当后续再次请求该资源时,请求头增加字段 if-modified-since 字段,值为之前返回的 last-modified 字段的值
	服务端对比该最后修改时间,若一致则证明未修改,告知浏览器使用缓存,并返回304,否则返回更新的资源,并修改 last-modified 的为新时间
    缺点:
    1. 时间精度只能精确到秒
    2. 以修改时间为依据,而不是以内容是否改变为依据
  1. Etag:
    etag是基于资源的内容编码生成的一串唯一标识字符串,内容不同则etag不同,解决了 last-modified 无法检测内容改变的缺点
    资源响应头中包含 etag 字段,值为唯一标识字符串,如
etag: "FllOiaIvA1f-ftHGziLgMIMVkVw_"
再次请求该资源时,请求头上增加字段 if-no-match 字段,值为之前返回的 etag 字段的值
服务端对比该标识字符串,若一致则表明资源未更新,缓存可用,返回304,浏览器使用缓存;若不一致则返回新的资源,并修改 etag 字段为新值
优点:
 	精确感知资源的内容变化
缺点:
	生成标识字符串增加了服务器的开销

访问刷新分析

  1. 标签进入、输入url回车进入
    (1) 先检查强缓存
    a. 若有 cache-control
    若有 no-store,则不使用缓存,向服务器请求最新资源,返回 200 ok
    若有 no-cache,则不使用缓存,向服务器协商缓存,未过期则使用缓存并返回 304,过期则返回新资源 200
    检查失效时间 max-age / s-maxage ,若未失效则使用缓存,返回 200 from chache
    b. 若无 cache-control 则 检查 expires ,检查失效时间戳是否到期,未失效则使用缓存,返回 200 from cache

     (2) 若本地缓存已经过期,则使用协商缓存路线
     根据 last-modified / etag 检查资源是否过期,若未过期则使用缓存,返回304 not modified
     (3) 若强缓存和协商缓存都过期,则返回新资源,状态码200 ok,并响应头中更新协商缓存的失效时间
    
  2. 按刷新按钮、F5 刷新、网页右键“重新加载”
    浏览器会将资源请求头设置为 cache-control: max-age=0 来使缓存过期,走协商缓存路线,向服务器检查资源是否过期

  3. ctrl + F5 强制刷新
    将请求头设置 no-cache ,强制获取最新的资源,发送请求头如下

	cache-control: no-cache
	pragma: no-cache

输入url到页面加载完成发生了什么谈跨域、缓存、DNS、http与https(版本,状态码,请求头)以及TCP/IP(三次握手四次挥手)

三、DNS域名解析

解析出映射的IP地址,浏览器缓存 -> 操作系统缓存 -> 本地DNS缓存 递归查询
本地DNS服务器 -> 根DNS服务器 -> *DNS服务器 -> 权威DNS服务器 迭代查询
输入url到页面加载完成发生了什么谈跨域、缓存、DNS、http与https(版本,状态码,请求头)以及TCP/IP(三次握手四次挥手)
输入url到页面加载完成发生了什么谈跨域、缓存、DNS、http与https(版本,状态码,请求头)以及TCP/IP(三次握手四次挥手)

四、建立TCP连接(三次握手)

鉴于好多面试都是三次握手,四次挥手一起问的,所以关闭连接的四次挥手也在这里一起讲了。TCP的三次握手、四次挥手
输入url到页面加载完成发生了什么谈跨域、缓存、DNS、http与https(版本,状态码,请求头)以及TCP/IP(三次握手四次挥手)
序列号seq: 占4个字节,用来标记数据断的顺序。TCP把连接发送的数据字节都会编上一个序列号,seq就是这段数据报文的第一个字节的序列号。

确认号ack:占4个字节,期待收到对方下一数据报文的第一个字节的序列号。

确认包ACK:占1位,仅当ACK=1时,确认号字段才有效。ACK=0时,确认号无效。

同步包SYN:连接建立时用于同步序号。当SYN=1,ACK=0时表示:这是一个连接请求报文段。若同意连接,则在响应报文段中使得SYN=1,ACK=1。因此,SYN=1表示这是一个连接请求,或连接接受报文。SYN这个标志位只有在TCP建产连接时才会被置1,握手完成后SYN标志位被置0。

终止包FIN:用来释放一个连接。FIN=1表示:此报文段的发送方的数据已经发送完毕,并要求释放运输连接

PS:ACK、SYN和FIN这些大写的单词表示标志位,其值要么是1,要么是0;ack、seq小写的单词表示序号。

三次握手过程理解
输入url到页面加载完成发生了什么谈跨域、缓存、DNS、http与https(版本,状态码,请求头)以及TCP/IP(三次握手四次挥手)
第一次握手:建立连接时,客户端发送SYN包(seq=x)到服务器,并进入SYN_SENT状态,等待服务器确认;

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

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

四次挥手过程理解
输入url到页面加载完成发生了什么谈跨域、缓存、DNS、http与https(版本,状态码,请求头)以及TCP/IP(三次握手四次挥手)
第一次挥手:客户端发送释放连接报文FIN=1,并停止发送数据。释放数据报文首部,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1)此时,客户端进入终止等待1的状态

第二次挥手: 服务端接受到释放连接报文后,发送确认包ACK(序号ack=u+1)并带上自己的序列号seq=v;此时,服务端进入关闭等待状态;客户端接受到确认请求后,进入终止等待2状态。

第三次挥手:服务端将最后的数据发送完之后,服务端发送释放连接报文FIN=1,并携带确认包ACK=1,ack=u+1;由于在半关闭的状态,可能还会发送一些数据,这里假设是seq=w;此时,服务端进入最后确认状态。

第四次挥手:客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。等待2MSL后进入CLOSED阶段,服务器接收到最后确认包之后,也进入CLOSED阶段,(服务器的关闭比客户端的早)连接关闭。

ps:为何握手三次,挥手四次?(简单说:释放连接需要时间准备)

五、浏览器发起http请求

这里要详细讲讲http的消息结构以及协议、版本之间的区别。关于http相关的知识,是前端人员必须掌握的,也是重点之一。

  1. http协议是什么?
    超文本传输协议,是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范。
  2. http和https的区别
    输入url到页面加载完成发生了什么谈跨域、缓存、DNS、http与https(版本,状态码,请求头)以及TCP/IP(三次握手四次挥手)
  3. http版本区别
    输入url到页面加载完成发生了什么谈跨域、缓存、DNS、http与https(版本,状态码,请求头)以及TCP/IP(三次握手四次挥手)
    输入url到页面加载完成发生了什么谈跨域、缓存、DNS、http与https(版本,状态码,请求头)以及TCP/IP(三次握手四次挥手)
  4. http消息结构
    http请求报文由三部分组成:请求行、请求头、请求主体
    输入url到页面加载完成发生了什么谈跨域、缓存、DNS、http与https(版本,状态码,请求头)以及TCP/IP(三次握手四次挥手)
  • 请求行包括请求方法、请求URL、协议名称以及版本号;
  • 请求头就是报文头若干个属性(下面会详细列出),如Cache-Control、referer
  • 请求主体就是URL携带的参数,param1=value1&param2=value2
    http响应报文包括响应行、响应头、响应体
    输入url到页面加载完成发生了什么谈跨域、缓存、DNS、http与https(版本,状态码,请求头)以及TCP/IP(三次握手四次挥手)
  • 响应行包括协议名称、版本号、状态码以及状态描述。
  • 响应头就是报文头若干个属性(下面会详细列出),如Etag、cache-controll、Set-Cookie
  • 响应主体就是服务器返回的数据
  1. http首部
    通用首部 :请求报文和响应报文两方都会使用的首部。
    每个属性具体详解输入url到页面加载完成发生了什么谈跨域、缓存、DNS、http与https(版本,状态码,请求头)以及TCP/IP(三次握手四次挥手)
    请求首部:也是请求头;用于说明是谁或什么在发送请求、请求源自何处,或者客户端的洗好及能力。服务器可以根据请求首部给出的客户端信息,试着为客户端提供更好的响应。每个属性具体详解
    输入url到页面加载完成发生了什么谈跨域、缓存、DNS、http与https(版本,状态码,请求头)以及TCP/IP(三次握手四次挥手)输入url到页面加载完成发生了什么谈跨域、缓存、DNS、http与https(版本,状态码,请求头)以及TCP/IP(三次握手四次挥手)
    响应首部:也是响应头;用于补充响应的附加信息、服务器信息,以及对客户端的附加要求等信息。这些首部有助于客户端处理响应,并在将来发起更好的请求。每个属性的具体详解
    输入url到页面加载完成发生了什么谈跨域、缓存、DNS、http与https(版本,状态码,请求头)以及TCP/IP(三次握手四次挥手)
    实体首部:针对请求报文和响应报文的实体部分使用的首部。能够对资源使用的各种有效的请求方法。总之,实体首部可以告知报文的接受者它在对什么进行处理。每个属性具体详解
    输入url到页面加载完成发生了什么谈跨域、缓存、DNS、http与https(版本,状态码,请求头)以及TCP/IP(三次握手四次挥手)
  2. 响应状态码:状态码详情

六、HTML页面渲染

1. Browser进程下载html文件并将文件发送给renderer进程

2. renderer进程的GUI进程开始解析html文件来构建出DOM

3. 当遇到外源css时,Browser进程下载该css文件并发送回来,GUI线程再解析该文件,在这同时,html的解析也同时进行,但不会渲染(还未形成渲染树)

4. 当遇到内部css时,html的解析和css的解析同时进行

5. 继续解析html文件,当遇到外源js时,Browser进程下载该js文件并发送回来,此时,js引擎线程解析并执行js,因为GUI线程和js引擎线程互斥,所以GUI线程被挂起,停止继续解析html。直到js引擎线程空闲,GUI线程继续解析html。

6. 遇到内部js也是同理

7. 解析完html文件,形成了完整的DOM树,也解析完了css,形成了完整的CSSOM树,两者结合形成了render树

8. 根据render树来进行布局,若在布局的过程中发生了元素尺寸、位置、隐藏的变化或增加、删除元素时,则进行回流,修改

9. 根据render树进行绘制,若在布局的过程中元素的外观发生变换,则进行重绘

10. 将布局、绘制得到的各个简单图层的位图发送给Browser进程,由它来合并简单图层为复合图层,从而显示到页面上

11. 以上步骤就是html文件解析全过程,完成之后,如若当页面有元素的尺寸、大小、隐藏有变化时,重新布局计算回流,并修改页面中所有受影响的部分,如若当页面有元素的外观发生变化时,重绘
 PS:更深的可自行去了解浏览器运行机制。

本文地址:https://blog.csdn.net/qq_31392495/article/details/109217295