美文网首页
输入url到渲染出页面的整个过程

输入url到渲染出页面的整个过程

作者: miao8862 | 来源:发表于2021-05-31 23:30 被阅读0次

    1. URL解析

    第一步是将URL中的每一部分给解析出来,比如:
    https://user:pass@xxx.com:80/index.html?name=xx&age=11#top

    • 协议:说明使用的协议https/http/ftp等,这个例子中为httpshttps协议比http其实是多了一层ssl或tls
    • 登录信息(认证):@前面这一部分user:pass,一般我们不用管
    • 域名:服务器地址,xxx.com
    • 端口:范围0-65535,用来识别应用在服务器哪个进程开启,http默认端口为80https默认443ftp默认21,比如https://www.baidu.com/,浏览器会默认访问443端口
      image.png
    • 请求资源的文件路径:/index.html
    • 查询字符串:?后的键值对,由&分隔,name=xx&age=11
    • 哈希值(也称锚点):服务器很少使用,一般是客户端页面之间使用,比如现在流行的单页应用的router,很多原理就是通过监听哈希值改变页面片段来实现的

    url编码解析

    针对URL中一些不识别的字符,比如中文或特殊字符,我们往往需要进行编码解析,解析方式一般有两种:

    • encodeURI和decodeURI
      encodeURI是对整个URL地址进行编码解析,主要是用来解析空格中文字符的,比如:
    let url = "http://xxx.com/index? name=小花&&age=11&&from=http://www.baidu.com/"
    
    // 对整个URL编码:处理空格和中文
    console.log(encodeURI(url)) // http://xxx.com/index?%20name=%E5%B0%8F%E8%8A%B1&&age=11&&from=http://www.baidu.com/
    
    • encodeURIComponent
      encodeURIComponent主要针对的是字符串参数部分的编码,可以用来处理一些特殊字符,比如:/等,如果不处理,浏览器会将这个http://xxx.com/index? name=小花&&age=11&&from=http://www.baidu.com/识别成两个url地址http://xxx.com/indexhttp://www.baidu.com/
    // 针对字符串参数部分的编码
    url = `http://xxx.com/index? name=${encodeURIComponent('小花')}&&age=11&&from=${encodeURIComponent('http://www.baidu.com/')}`
    console.log(url)  // http://xxx.com/index? name=%E5%B0%8F%E8%8A%B1&&age=11&&from=http%3A%2F%2Fwww.baidu.com%2F
    

    扩展:URL,URN,URI的区别

    • URL:统一资源定位符,定义了获取资源的方式http://和资源存放地址xxx.com/index
    • URN:统一资源名称,使用特定命名空间的名字标识资源,但不包括获取方式,比如:xxx.com/index#top
    • URI:统一资源标识符,URLURN都是URI的子集,也就是https://user:pass@xxx.com:80/index.html?name=xx&age=11#topURI
      但在日常中,我们可以笼统地认为URL就是URI

    2. 查找浏览器缓存

    浏览器缓存分为强缓存和协商缓存两种,当发送一个请求前,会先查看浏览器中是否有缓存,如果有,则从缓存中获取资源,否则,才重新发送请求。
    缓存位置一般为: 内存缓存(memory cache)和硬盘缓存(disk cache)

    • 打开网页时:会首先从硬盘缓存disk cache中查看是否缓存命中,如果有则使用,否则发送网络请求
    • 当普通刷新网页(F5)时:因为网页标签tab未关闭,所以可以会优先使用内存缓存,如果没有才会去硬盘缓存中查看是否有缓存,如果都没有才会发送网络请求
    • 当强制刷新网页(ctrl + F5)时:浏览器不使用缓存,因为发送的请求头中会带有cache-control: no-cache,服务器直接返回200和最新内容

    设置缓存的方式

    浏览器缓存分为强缓存和协商缓存两种:

    1. 强缓存:
    • expires:http1.0的特性,通过服务端设置响应头expires缓存过期时间,在这个时间前客户端不再发送请求,而是直接使用缓存; 缺点是这个过期时间是服务端根据服务端时间来设置的,而客户端浏览器则是通过客户端本地时间来判断是否过期的,如果本地时间错误,就会造成缓存失效;
    • cache-control:http 1.1的特性,是为了解决expires存在的问题而出现的,这通过设置一个cache-control: max-age=2592000,设置一个相对第一次获取资源后的存活时间2592000(s),即30天后缓存失效,cache-control的优先级高于expirescache-control的值一般有以下这些:
      • max-age: 设置客户端缓存有效时间
      • s-maxage:设置代理服务器缓存有效时间(仅在代理服务器中生效)
      • no-cache:绕开客户端缓存,直接向服务器确认该资源是否过期(还可以使用协商缓存)
      • no-store:不仅绕开客户端缓存,还不允许服务器缓存,即不使用任何缓存,只允许重新请求并下载资源
      • public、private:是针对资源是否能被代理服务器缓存的一组对立设置,如果为public,即可被浏览器缓存,也可被代理服务器缓存;如果为private,则只能被浏览器缓存,private为默认值。
    1. 协商缓存
    • Last-Modified
      http1.0的特性,由服务器发送一个上次修改时间Last-Modified标识给客户端,客户端下次发送请求时,将这个时间携带在请求头If-Modified-Since上,由服务器比对两次时间,如果有修改,则重新发送更新后的资源,否则返回304告知使用缓存。
      缺点是:

      1. Last-Modified的时间的最小间隔只能标识到1s,如果服务器在1s内修改了文件,那么客户端是无法拿到最新修改内容的。
      2. 修改了文件,但是后面我又修改回去,然后关闭文件,实际上相当于未修改文件,但由于修改时间变了,服务器会更新Last-Modified,导致客户端重新发请求。

      以上两点,总结来说,就是服务器无法真正感知文件的变化。

    • ETag
      http1.1的特性,为了解决Last-Modified存在的问题,服务器使用ETag哈希值来识别文件是否被修改过,客户端再次请求时会携带ETag的值到请求头If-None-Match,服务器比对两次文件哈希值,如果有修改,则重新发送资源,否则返回304使用缓存

    请求页面时,会先检查有没有强缓存,如果没有强缓存或强缓存失效时,才会检查有没有协商缓存,如果协商缓存失效或不存在时,才会重新请求。

    如何避免缓存

    一般html等静态资源文件我们是不做缓存的,这样是保证每一次html都是一次新请求,可以通过以下方式来避免缓存:

    1. 服务器资源更新后,让资源名称和之前的不一样,使用webpack给打包后的文件名添加hash + name
    2. 每次服务器资源更新后,在导入html等静态资源时,设置一个后缀(时间戳、版本号或随机数)
    <script src="index.js?145532685">
    <script src="index.js?version='1.0.0'">
    
    1. 设置强缓存响应头:
      Cache-Control: no-cache, no-store, must-revalidate
    2. 不使用强缓存,使用协商缓存,由服务器决定是否使用缓存

    3. DNS解析

    为什么要进行DNS解析?
    一台主机的真正地址是IP,但IP是一些数字,不利用于人们记忆,所以就有了域名服务器,它是将域名和IP做了个映射关系,方便通过域名找到IP。

    DNS解析过程,其实就是将域名解析到IP地址:
    1.浏览器缓存 - 浏览器缓存DNS记录一段时间
    2.操作系统缓存 - 文件(比如Hosts文件)查找是否有该域名和对应IP
    3.路由器缓存 - 一般路由器也会缓存域名信息
    4.ISP DNS缓存 - 本地DNS服务器缓存去找,比如电信、移动等
    5.都没有找到,则向根域名服务器查找域名对应IP,根域名服务器把请求转发到下一级查找IP
    www.baidu.com查找顺序是: 根域名服务器(.)-> .com(顶级域名) -> .baidu.com(二级域名) -> www.baidu.com(三级),这里的查找顺序是通过本地DNS服务器来承上启下的,每个域名服务器都要通过本地DNS服务器来通信,如下图:
    其中根域名服务器在域名地址中最后一个点,通常被省略,比如www.baidu.com的完整域名应该是www.baidu.com.

    迭代查询

    其中1-5是递归查询,5操作则是迭代查询

    扩展:DNS性能优化

    每次DNS解析都要花费20-120ms,当存在多个不同的域名,这个花费时间会逐渐增长,想要优化它,我们第一想到的是减少使用不同的域名,但在实际项目中,我们往往不推荐这种,因为要考虑到一些服务拆分的其它因素:

    • 资源的合理利用
    • 抗压能力加强
    • 提高HTTP并发数等

    所以,服务器拆分是很有必要的,我们往往使用另一种方式:dns-prefetch预获取的方式来优化DNS解析,比如京东官网:

    <link rel="dns-prefetch" href="//static.360buyimg.com">
    
    image.png

    4. 浏览器与服务器交互的过程

    1. 首先浏览器利用tcp协议通过三次握手与服务器建立TCP连接
        http请求包括header和body。header中包括请求的方式(get和post)、请求的协议 (http、https、ftp)、请求的地址ip、缓存cookie。body中有请求的内容。
    2. 连接建立后,浏览器根据解析到的IP地址和端口号发起http的get请求.
    3. 服务器接收到http请求之后,开始搜索html页面,并使用http返回响应报文
    4. 若状态码为200显示响应成功,浏览器接收到返回的html页面之后,开始进行页面的渲染

    5. 浏览器页面渲染过程

    1. 浏览器根据深度遍历的方式把html节点遍历成DOM树
    2. css解析成CSS DOM树
    3. dom树CSS DOM树构造成render树
    4. JS根据得到的render树 计算所有节点在屏幕中的位置,进行布局(回流)
    5. 遍历render树并调用硬件API绘制所有节点(重绘)

    参考:
    https://www.jianshu.com/p/308212675adb
    https://segmentfault.com/a/1190000014311983
    https://www.cnblogs.com/qing-5/p/11126524.html

    相关文章

      网友评论

          本文标题:输入url到渲染出页面的整个过程

          本文链接:https://www.haomeiwen.com/subject/wjzucltx.html