从输入url到发送请求,发生了什么?这个问题的覆盖面非常的广(包含DNS、SSL/TLS、HSTS、QUIC等),可以说是涉及到前端的方方面面,很适合用来考察前端的的知识体系。总的来说分为以下几个过程:

  • DNS解析查询到IP地址

  • TCP连接到服务器

  • 发送http请求

  • 服务器处理请求并返回响应内容

  • 浏览器解析渲染页面

输入地址到获取IP

DNS LOOKUP

网络通信大部分是基于TCP/IP协议的,是基于IP地址进行网络连接的。所以网络中只能识别IP地址,而不能识别域名(HTTP请求的信息里面Remote Address就是服务器的IP地址)。所以我们需要一个DNS服务器,自动把我们的域名翻译成相应的IP地址。

DNS,英文为Domain Name System,翻译为域名系统。

DNS是由域名解析器和域名服务器组成的。域名服务器是指保存有该网络中所有主机的域名和对应IP地址,并具有将域名转换为IP地址功能的服务器。将域名映射为IP地址的过程就称为“域名解析”。

DNS解析过程

例如输入地址,www.example.com,DNS客户端会进行如下操作:

  • 浏览器缓存 在自己的缓存中查找是否有该域名对应的IP地址

  • 系统缓存 当浏览器缓存中无域名对应IP则会自动检查用户计算机系统Hosts文件DNS缓存是否有该域名对应IP

  • 路由器缓存 当浏览器及系统缓存中均无域名对应IP则进入路由器缓存中检查,以上三步均为客服端的DNS缓存

  • 互联网服务提供商 当在用户客服端查找不到域名对应IP地址,则将进入ISP DNS缓存中进行查询。比如你用的是电信的网络,则会进入电信的DNS缓存服务器中进行查找

  • 根域名服务器 当以上均未完成,则进入根服务器进行查询。全球仅有13台根域名服务器,1个主根域名服务器,其余12为辅根域名服务器。根域名收到请求后会查看区域文件记录,若无则将其管辖范围内顶级域名(如.com)服务器IP告诉本地DNS服务器

  • 顶级域名服务器 顶级域名服务器收到请求后查看区域文件记录,若无则将其管辖范围内主域名服务器的IP地址告诉本地DNS服务器

  • 主域名服务器 主域名服务器接受到请求后查询自己的缓存,如果没有则进入下一级域名服务器进行查找,并重复该步骤直至找到正确纪录

预加载,dns-prefetch

现代浏览器都支持DNS的预解析,使用方法为在html代码里面加入:

<link rel="dns-prefetch" href="//example.com">

HSTS,HTTP严格传输安全

HSTS,英文为HTTP Strict Transport Security,翻译为HTTP严格传输安全。HSTS的作用是强制客户端使用HTTPS与服务器创建连接(是一种浏览器行为)。开启HSTS的方法是,当客户端通过HTTPS发出请求时,在服务器返回的超文本传输协议(HTTP)响应头中包含Strict-Transport-Security字段。

为什么要使用HSTS

不少网站通过HTTPS对外提供服务,但用户在访问某个网站的时候,在浏览器里面输入的是网站域名(如www.example.com)而不是完整的URl(如https://www.example.com),因此浏览器先向网站发起一次HTTP请求,在得到服务器的重定向响应后,再由浏览器发起一次HTTPS请求并得到最终的响应内容。

危险在于:由于在建立起HTTPS连接之前存在一次明文的HTTP请求和重定向,使得攻击者可以以中间人的方式劫持这次请求,从而进行后续的攻击,例如窃听数据,篡改请求和响应,跳转到钓鱼网站等。

HSTS的作用

我们期望的浏览器行为是,当用户让浏览器发起HTTP请求的时候,浏览器将其转换为HTTPS请求,直接略过上述的HTTP请求和重定向,从而使得中间人攻击失效,规避风险。

HSTS最为核心的是一个HTTP响应头(HTTP Response Header)。正是它可以让浏览器得知,在接下来的一段时间内,当前域名只能通过HTTPS进行访问,并且在浏览器发现当前连接不安全的情况下,强制拒绝用户的后续访问要求。

HSTS Header的语法如下:Strict-Transport-Security: <max-age=>[; includeSubDomains][; preload],其中:

  • max-age是必选参数,是一个以秒为单位的数值,它代表着HSTS Header的过期时间,通常设置为1年,即31536000秒。

  • includeSubDomains是可选参数,如果包含它,则意味着当前域名及其子域名均开启HSTS保护。

  • preload是可选参数,只有当你申请将自己的域名加入到浏览器内置列表的时候才需要使用到它。

示例头信息:Strict-Transport-Security: max-age=31536000; includeSubDomains; always;

Preload List 提升 HSTS 的安全性

HSTS并不代表安全了,因此浏览器中有HSTS信息时候才会直接使用HTTPS请求,如果浏览器中没有HSTS信息,则依然会进行HTTP明文请求和重定向。

解决办法是,申请加入到Preload List,它由Google Chromium维护,FireFox、Safari、IE等主流浏览器均在使用。它是在浏览器里面内置的一个列表,只要是在这个列表里的域名,无论何时何种情况,浏览器都只使用HTTPS请求发起连接。

配置HSTS的注意点

注意点1

HSTS存在一个比较薄弱的环节,那就是浏览器没有当前网站的HSTS信息的时候,或者第一次访问网站的时候,依然需要一次明文的HTTP请求和重定向才能切换到HTTPS,以及刷新HSTS信息。而就是这么一瞬间却给攻击者留下了可乘之机,使得他们可以把这一次的HTTP请求劫持下来,继续中间人攻击。

注意点2

在生产环境下使用HSTS应当特别谨慎,因为一旦浏览器接收到HSTS Header(假如有效期是1年),但是网站的证书又恰好出了问题,那么用户将在接下来的1年时间内都无法访问到你的网站,直到证书错误被修复,或者用户主动清除浏览器缓存。因此,建议在生产环境开启HSTS的时候,先将max-age的值设置小一些,例如5分钟,然后检查HSTS是否能正常工作,网站能否正常访问,之后再逐步将时间延长,例如1周、1个月,并在这个时间范围内继续检查HSTS是否正常工作,最后才改到1年。

QUIC

HTTP 常用的是 TCP 协议,假设客户端的发送了 3 个 TCP 片段,编号分别是 1、2、3,如果编号为 1 的包传输时丢了,即便编号 2 和 3 已经到达也只能等待,因为 TCP 协议需要保证顺序。这个问题在 HTTP pipelining 下更严重,因为 HTTP pipelining 可以让多个 HTTP 请求通过一个 TCP 发送,比如发送两张图片,可能第二张图片的数据已经全收到了,但还得等第一张图片的数据传到。

为了解决 TCP 协议的性能问题,Chrome 团队提出了 QUIC 协议,它是基于 UDP 实现的可靠传输,比起 TCP,它能减少很多来回(round trip)时间,还有前向纠错码(Forward Error Correction)等功能。

Quic,英文quick udp internet connection,翻译为快速UDP互联网连接。Quic相比现在的HTTP2.0 + TCP + TLS协议有如下优势:

  • 减少了TCP三次握手及TLS握手时间

  • 改进的拥塞控制

  • 避免队头阻塞的多路复用

  • 连接迁移

  • 向前冗余纠错

SSL/TLS协议

SSL,英文全称为Secure Sockets Layer,翻译为安全套接层

TLS,英文全称为Transport Layer Security,翻译为传输层安全协定

HTTP使用明文进行传输,存在信息安全隐患,黑客可以窃听、篡改、冒充,SSL/TLS协议就是为了解决HTTP的传输安全而设计的(HTTPS中的S就是这个协议)。SSL/TLS协议为HTTP传输添加了信息加密、通信校验机制、配备身份证书

怎么确定证书的安全?

HTTPS的SSL证书可以自行颁发,自行颁发的SSL证书虽然能够实现加密传输功能,但得不到浏览器的信任,会出现以下提示:

SSL证书也可以由CA机构颁发,每个浏览器都维护着一份通过根证书认证的厂商清单,当通过HTTPS发起请求的时候,浏览器会对CA证书进行校验,如果这个CA证书的厂商不在根证书认证列表中,则浏览器会提示不安全(如下为安全和不安全的显示)

ARP,地址解析协议

ARP,英文全称为Address Resolution Protocol,翻译为地址解析协议

光靠IP地址是无法进行通信的,因为IP地址并不和某台设备绑定,比如你的笔记本的IP在家中是192.168.1.1,但到公司就变成172.22.22.22了,所以在底层通信时需要使用一个固定的地址,这就是MAC(media access control)地址,每个网卡出厂时的MAC地址都是固定且唯一的。

当一台电脑加入网络时,需要通过ARP协议告诉其它网络设备它的IP及对应的MAC地址是什么,这样其它设备就能通过IP地址来查找对应的设备了。

浏览器解析渲染页面

浏览器工作大流程

1、http请求从服务器上获取响应后,浏览器会解析如下三个东西:

  • 一个是HTML/SVG/XHTML,事实上,Webkit有三个C++的类对应这三类文档。解析这三种文件会产生一个DOM树(DOM Tree)

  • CSS,解析CSS会产生CSS规则树(CSS Rule Tree)

  • Javascript脚本,主要是通过DOM API和CSSOM API来操作DOM Tree和CSS Rule Tree

2、解析完成后,浏览器引擎会通过DOM Tree 和 CSS Rule Tree 来构造 Rendering Tree

  • 渲染树(Rendering Tree)并不等同于DOM树,渲染树只包括需要显示的节点和这些节点的样式信息,因此,head部分和样式为display:none的元素不在渲染树中

  • CSS Rule Tree主要是为了完成匹配并把CSS Rule附加上Rendering Tree上的每个元素上

  • 然后计算每个元素的位置,又叫layout和reflow过程

3、最后通过调用操作系统Native GUI的API绘制

构建DOM

浏览器会遵守一套步骤将HTML文件转换为DOM树。

字节数据 =》字符串 =》TOKEN => Node => DOM

1、网络中传输的都是0和1这样的字节数据,浏览器从磁盘或网络读取原始字节,并根据文件的指定编码(如UTF-8)将它们转换成字符串(也就是我们的代码)。

2、将字符串转换成TOKEN,例如<html><body>等,Token 中会标识出当前 Token 是“开始标签”或是“结束标签”亦或是“文本”等信息。

3、生成节点对象(Node)并构建DOM,每个Token被生成后,会立刻消耗这个Token创建出节点对象。

假设有段HTML文本:

<html>
<head>
    <title>Web page parsing</title>
</head>
<body>
    <div>
        <h1>Web page parsing</h1>
        <p>This is an example Web page.</p>
    </div>
</body>
</html>

上面这段HTML会解析成这样:

构建CSSCOM

DOM会捕获页面的内容,但浏览器还需要知道页面如何展示,所以需要构建CSSOM。构建CSSOM的过程与构建 DOM的过程非常相似,当浏览器接收到一段CSS,浏览器首先要做的是识别出Token,然后构建节点并生成CSSOM。

注意:CSS匹配HTML元素是一个相当复杂和有性能问题的事情。所以,你就会在N多地方看到很多人都告诉你,DOM树要小,CSS尽量用id和class,千万不要过渡层叠下去。(例如div p span span{}这样的css样式是不可取的)

浏览器渲染

渲染的流程基本上如下:

  • 计算CSS样式

  • 构建Render Tree

  • Layout,定位坐标和大小,是否换行,各种position, overflow, z-index属性

  • 绘制页面

浏览器绘制页面过程中,存在两个重要概念,一个是Reflow(重排或回流,是一个概念,叫法不同),另一个是Repaint(重绘)

**重绘** 页面一部分重新画,一般是样式的更改,但元素的几何尺寸没变。

**重排或回流** 某个元素的几何尺寸发生变化,我们需要重新验证并计算Render Tree(HTML使用的是流式布局,如果某元素的几何尺寸发生了变化,需要重新布局,也就叫reflow)。

Reflow的成本比Repaint的成本高得多的多。DOM Tree里的每个结点都会有reflow方法,一个结点的reflow很有可能导致子结点,甚至父点以及同级结点的reflow。

浏览器如果渲染过程中遇到JS文件怎么处理

渲染过程中,如果遇到<script>就停止渲染,执行JS代码。因为浏览器有GUI渲染线程与JS引擎线程,为了防止渲染出现不可预期的结果,这两个线程是互斥的关系。

JavaScript的加载、解析与执行会阻塞DOM的构建,也就是说,在构建DOM时,HTML解析器若遇到了JavaScript,那么它会暂停构建DOM,将控制权移交给JavaScript引擎,等JavaScript引擎运行完毕,浏览器再从中断的地方恢复DOM构建。

JavaScript还可以更改样式,也就是CSSOM。因为不完整的CSSOM是无法使用的,如果JavaScript想访问 CSSOM并更改它,那么在执行JavaScript时,必须要能拿到完整的CSSOM。如果浏览器尚未完成CSSOM的下载和构建,而我们却想在此时运行脚本,那么浏览器将延迟脚本执行和DOM构建,直至其完成CSSOM的下载和构建。

为什么操作DOM慢

DOM 是属于渲染引擎中的东西,而 JS 又是 JS 引擎中的东西。当我们用 JS 去操作 DOM 时,本质上是 JS 引擎和渲染引擎之间进行了“跨界交流”。这个“跨界交流”的实现并不简单,它依赖了桥接接口作为“桥梁”。

过“桥”的开销本身就是不可忽略的。我们每操作一次DOM,都要过一次“桥”,过“桥”的次数一多,就会产生比较明显的性能问题。

减少重绘重排

1、不要一条一条地修改DOM的样式。与其这样,还不如预先定义好css的class,然后修改DOM的className。

2、把DOM离线后修改。如使用documentFragment对象在内存里操作DOM。先把DOM给display:none(有一次reflow),比如修改100次,然后再把他显示出来。

3、不要把DOM结点的属性值放在一个循环里当成循环里的变量。

问题整理

HTTP创建状态及代表意思

  • 200 请求被成功地完成,所请求的资源发送回客户端
  • 204 请求执行成功但是没有数据
  • 304 自上次请求网页没有修改过,直接从缓存获取
  • 400 客户端请求报错
  • 401 请求未经授权
  • 403 禁止访问
  • 404 资源未找到
  • 500 服务器内容错误
  • 503 服务不可用

如何确定http协议类型

参考:

[1] 从输入URL到页面加载完成的过程中都发生了什么事情

[2] 从输入URL到页面加载的过程

[3] DNS協定

[4] HSTS详解

[5] HTTP严格传输安全

[6] SSL/TLS协议运行机制的概述

[7] QUIC协议原理分析

[8] 浏览器的渲染原理简介

[9] How browsers work

[10] 了解SSL证书

Author:tenado
CeateTime:2019-05-15
Link:https://www.kelede.win/posts/%E8%BE%93%E5%85%A5url%E5%90%8E%E5%8F%91%E7%94%9F%E4%BA%86%E4%BB%80%E4%B9%88/
License:本站博文无特别声明均为原创,转载请保留原文链接及作者
Previous:深入了解promise Next:HTTP1.0和HTTP2.0的区别