A little bit of history
50多年前,ARPA网络被创建了。它是一个早期的数据包交换网络而且是第一个实现了TCP/IP的网络。这个网络是连接到加州大学和斯坦福大学的。20年之后,Tim Berners-Lee提出了一个草案---这就是著名的万维网。50多年来,因特网已经走过了很长的一段路,从一来是给两台计算机交换数据,到现在超7500万服务器,38 亿人使用互联网以及 13 亿个网站。
这一节,我们会分析现代浏览器采用了哪些技术来进行优化,尤其是在网络层。最后,照例提出一下优化建议
概述
现代浏览器是为快速,高效和数据安全的网站设计的。成百上千的组件运行在不同的层级中,比如进程管理,GPU管道沙箱,音视频等等。现代浏览器看起来更像是操作系统而不是一个应用软件了
影响浏览器整体性能的因素是几个大组件: 转换,布局,样式计算,代码执行(JS或者WebAssembly),渲染,以及网络栈 开发者一般认为网络栈是性能瓶颈,这是很正常的,因为从网络抓取所有的资源会堵塞渲染剩下的步骤。要让网络层更高效,那么就不能仅仅是一个套接字管理。它看起啦只是一个获取资源的简单机制,实际上它却是一个自身优化原则,API和服务的集成平台
作为开发者,我们不需要担心独立的TCP或UDP包,请求格式,缓存以及其他所有的事情。浏览器负责了这些复杂的累活儿,这样开发者就只用关心自己的业务开发。但是理解底层机制,可以帮助你写出更快更安全的应用
当用户使用后浏览器时,发生了这些事情:
- 用户在地址栏输入了URL
- 浏览器根据URL去检查本地缓存,然后尝试去用本地副本去回应请求。
- 如果缓存不可用,浏览器从URL中获取域名,然后从DNS服务中获取IP地址。如果域名已经缓存了,就不用查询DNS了。
- 浏览器创建一个HTTP包,表明其在远程服务请求的网页。
- HTTP包被发送到TCP层,TCP层把自己的信息添加到包的顶部。这个信息是用来维护会话的。
- IP层再处理这个包,这一层主要是指出用户给服务器发送包的方式。这个信息也被保存在包的顶部。
- 这个包被发送到远程服务端
- 服务端一旦接受了包,就会用相似的行为做出回复
W3C提供了一个浏览器API及浏览器中每个请求背后的可视化计时和性能数据。让我们浏览下这些组件,因为每个组件在获取最佳用户体验方面扮演了重要的角色。
整个网络进程是非常复杂的,每一层都有可能成为性能瓶颈。这就是为什么浏览器使用各种手段提升性能,将网络层的影响最小化
套接字管理
先看一些术语:
- 源 — 由协议,域名和端口三方组成
- 套接字池 — 同一个源下面的套接字组(大多数浏览器限制池的最大尺寸是5)
JS和WebAssembly都不允许开发者去管理每一个套接字的生命周期,这是非常好的事情。这不仅让我们双手干净,而且允许浏览器来完成很多优化行为,包括套接字复用,请求优先级和延迟绑定,协议协商,强制连接限制及其它的优化措施。
实际上,现代浏览器走的更远,从套接字管理中分离了请求管理周期。套接字可以在池中组织,套接字池是根据请求源来分组的,每一个池也都强制限制自己的连接数和安全要求。排队,优先化等待的请求,然后和套接字池中的单个套接字绑定。如果不是服务器主动关闭这些连接,多个请求可以自动重用相同的套接字。
打开一个新的TCP连接会额外增加很多消耗,因此连接复用具有巨大的好处。一般浏览器默认使用了“keepalive” 的机制,来节省发起请求时打开连接的时间。打开TCP连接的平均时间是:
- 本地请求 —
23ms
- 洲际访问—
120ms
- 国际请求 —
225ms
这种结构带来了很多优化的机会。根据请求的权重,他们可以按照不同的顺序执行。浏览器可以根据所有的套接字来优化带宽分配,或者打开套接字等待请求。
这些都是浏览器来做的,我们什么都不用做。但是,我们可以根据它的原来来做一些有帮助的事情。选择正确的网略连接范式,类型以及传输的频率,正确的协议类型以及正确的服务器堆栈隧道/优化,都可以有效提升整个程序的性能。 有些浏览器走的更远。例如,Chrome 可以根据你的使用情况自我优化。跟你的昂展访问和浏览器模式,它可以猜测用户的行为,然后在用户执行前就采取行动。最简单的例子就是当用户的鼠标hover在一个link上时,预渲染这个页面。
网络安全和沙箱
允许浏览器管理独立的套接字,具有一个非常重要的目的:浏览器就可以针对不被信任的程序资源强制实施一套一致的安全和政策约束措施。例如,浏览器不允许直接直接访问原始套接字,这样会使得一些恶意应用访问任意端口。浏览器也强制了连接限制,这也保护了服务器不会因为用户访问量太大而资源枯竭。
浏览器格式化所有流出的请求以强制格式正确和一致的协议语义来保护服务器。同样地,浏览器会自动解码响应内容以保护用户免受可疑服务器的攻击。
TLS 协商
Transport Layer Security (TLS)是一个加密协议,为计算机网络提供了安全通信机制。这个协议已经在很多应用中大量使用了,其中就有网络浏览器。网站上会用TLS可以在保护服务器和浏览器之间的所有通信。 TLS握手包含以下步骤:
- 客户端发送一个’Client hello‘给服务端,附带着客户端随机值和支持的密码组合。
- 服务器响应了一个“Server hello”,伴随一个服务端的随机值。
- 服务端发送它的认证证书,并可能请求客户端也发送一个类似的证书。之后服务端发送“Server hello done”信息。
- 如果服务器像客户端请求证书,客户端就发送它。
- 客户端创建一个随机的 Pre-Master Secret ,并且用服务端证书中的公钥进行加密,加密后的 Pre-Master Secret发送到服务端。
- 服务端接受了Pre-Master Secret,服务器和客户端各自基于Pre-Master生成一个Master Secret和一个会话密钥
- 客户端发送一个“Change cipher spec” 的通知给服务端,标志客户端将会使用一个新的hash的会话密钥进行加密通信。客户端也会发送一个“Client finished”信息。
- 服务端接受了“Change cipher spec” 信息,然后使用会话密钥将记录层的安全状态切换到对称加密。然后服务端发送“Server finished”信息给客户端。
- 客户单和服务端现在可以通过他们建立的安全通道交换应用数据了。所有的数据都被会话密钥加密了。
每当发生任何验证失败的时候,用户会收到警告。比如服务器使用自签名的证书。
同源策略
如果两个页面具有相同的协议,端口(如果有指定的话),主机名是相同的,那么两者就是同源。
下面这些场景可能引起跨源:
<script src=”…”></script>
里面的 JavaScript 代码。语法错误的错误信息仅适用于同源脚本。<link rel=”stylesheet” href=”…”>
中的CSS。由于 CSS 的松散语法规则,跨域 CSS 要求正确的 Content-Type 头。各个浏览器的限制不同。<img>
中的图像-
<video>
和<audio>
中的媒体文件 -
<object>
,<embed>
和<applet>
的内置插件 - @font-face中的字体。一些浏览器允许跨源字体,但另一些是要求同源字体的
<frame>
和<iframe>
中的所有东西。可以使用X-Frame-Options 头信息来防止此种跨域交互
这个列表远远不够,它只是为了凸显工作中的“最小影响”原则。浏览器只是暴露了应用代码必须的API和资源:应用提供了数据和URL,浏览器格式化请求,处理了每一个连接的完整生命周期
注意,没有个独立的 “同源策略”的概念。相反了,有一系列相关的机制,强制约束DOM访问,cookie和回话状态管理,网络以及浏览器中的其他组件
资源和客户端状态缓存
最快的请求时不发送请求。在发送请求之前,浏览器自动的查看一下它的资源缓存,执行一些必要的验证,如何满足特定的条件,那么就返回本地缓存的副本。如果一个资源在缓存中不可用,那么发送一个网络请求,然后把响应内容自动放置于缓存中以备之后的访问(如果这是被允许的)。
- 浏览器自动为每个资源求值缓存指令
- 当条件允许时,浏览器自动重新恢复过期资源
- 浏览器自动管理缓存和资源回收的大小
管理一个高效和优化的资源缓存是很难的。谢天谢地,浏览器帮我们处理了这些,我们需要做的是确保我们的服务器返回合适的缓存指令。更多信息,查看客户端缓存。你可以给所有的页面添加上Cache-Control,ETag,和 Last-Modified 的响应头信息
最终,一个常见但是非常重要的浏览器功能是,它要负责验证,回话和cookie管理。浏览器为每一个源维护一个独立的“cookie jars”,提供必要的应用和服务端API去读写新cookie,会话和验证数据,自动添加和处理合适的HTTP头来自动处理整个流程
举个例子:
一个简单但是有效地例子,来说明浏览器延迟会话状态管理的便利:多个tab或者浏览器窗口可以共享一个认证会话,反之亦然;在一个tab中登出,将会让其他打开的页面的会话失效。
应用API和协议
沿着网络服务走,我们现在到了应用层的API和协议。我们已经知道,底层提供了大量的关键服务:套接字和连接管理,请求和回应流程,强制安全策略,缓存等等。每一次我们初始化一个HTTP或者一个XMLHttpRequest,一个长久激活的Server-Sent Event 或者WebSocket会话,或者打开一个WebRTC连接,我们就是在和部分或者所有这些底层服务进行交互。
没有单一的最好的协议或者API。每个复杂的程序都会基于不同的要求混合使用不同的传输协议:和浏览器缓存的交互,协议开销,消息延迟,可靠性,数据传输类型以及其它。一些协议拥有低数据传输延迟的特性(比如服务器推事件,WebSocket),但是可能不符合其它重要的场合,比如利用浏览器缓存或者支持任意情况下的二进制数据传输的能力。
提升安全性和性能的一些小建议
- 在请求中多使用 “Connection: Keep-Alive” 请求头。浏览器会默认这么做,需要确保服务器有相同的机制。
- 使用合适的Cache-Control, Etag 和 Last-Modified 头,节省浏览器下载的时间
- 花费时间优化你的网络服务。这里是真正发生奇迹的地方。注意这一过程是否针对每个程序和所传输的数据。
- 经常使用TLS。尤其是如果你的程序中包含有任意类型的认证。
- 研究浏览器所提供的安全策略并且在程序中强制实施。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!