欢迎大家前往腾讯云 社区,获取更多腾讯海量技术实践干货哦~

本文由腾讯IVWEB团队发表于云 社区专栏

作者:yangchunwen

HTTP协议是前端性能乃至安全中一个非常重要的话题,最近在看《web性能权威指南(High Performance Browser Networking)》,把其中关于HTTP部分的内容拿出来分享一下,加了一点自己的想法,当然没有《HTTP权威指南》讲得详细,但对于理解我们平常做的事情很有启发。预计会有两三篇文章,重点分别会涉及到HTTP 1.1、HTTPS、HTTP 2.0等内容,本篇主要涉及HTTP 1.1及其应用。

HTTP的历史

HTTP 0.9

HTTP的第一个版本被官方称为HTTP0.9,这是个只有一行的协议,例如:

GET /about/(超文本响应……)
(连接关闭……)

HTTP 0.9有几个要点:

  • 客户端/服务器、请求/响应协议
  • ASCII 协议,运行于TCP/IP链接之上
  • 设计用来传输超文本文档(HTML)
  • 服务器与客户端之间的连接在每次请求之后都会关闭

这个版本的HTTP主要用来传输文本,并且没有共用TCP连接。

HTTP 1.0

一个典型的HTTP 1.0请求过程如下:

GET /rfc/rfc1945.txt HTTP/1.0
User-Agent: CERN-LineMode/2.15 libwww/2.17b3
Accept: */* HTTP/1.0 200 OK
Content-Type: text/plain
Content-Length: 137582
Expires: Thu, 01 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 1 May 1996 12:45:26 GMT Server: Apache 0.84(超文本响应……)
(连接关闭……)

相对前一个版本,HTTP 1.0主要有以下几点变化:

  • 请求和相应可以由于多行首部字段构成
  • 响应对象前面添加了一个响应状态
  • 响应对象不局限于超文本
  • 服务器与客户端之间的连接在每次请求之后都会关闭
  • 实现了Expires等传输内容的缓存控制
  • 内容编码Accept-Encoding、字符集Accept-Charset等协商内容的支持

这时候开始有了请求及返回首部的概念,开始传输不限于文本(其他二进制内容)

HTTP 1.1

HTTP 1.1是当前大部分应用所使用的协议版本。相对前面的1.0版本,HTTP 1.1语义格式基本保持不变,但是它加入了很多重要的性能优化:持久连接、分块编码传输、字节范围请求、增强的缓存机制、传输编码及请求管道

实际上,持久链接在后来被反向移植到了HTTP1.0上

HTTP 2.0

HTTP 2.0 的主要目标是改进传输性能,实现低延迟和高吞吐量。HTTP 2.0作了很多性能角度的优化,另一方面,HTTP的高层协议语义并不会因为这次版本升级而受影响。所有HTTP首部、值,以及它们的使用场景都不会变。现有的任何网站和应用,无需做任何修改都可以在 HTTP 2.0 上跑起来。换句话说, 等以后我们的服务器、客户端(如浏览器)都支持HTTP 2.0的时候,我们不用为了利用 HTTP 2.0 的好处而修改标记,作很多额外的编码,却能享受到它带来的更低的延迟和更高的网络连接利用率交付!

HTTP 2.0的内容将在下篇或下下篇放出,本文不对其做过多润色

HTTP 1.1与前端性能

前面讲到,HTTP 1.1这个版本引入了大量增强性能的重要特性,其中包括:

  • 持久化连接以支持连接重用
  • 分块传输编码以支持流式响应
  • 请求管道以支持并行请求处理
  • 字节服务以支持基于范围的资源请求
  • 改进的更好的缓存机制

这里重点讲一下持久化、管道在前端性能优化中的一些应用

持久连接

所谓持久连接,就是重用 TCP连接,多个HTTP请求公用一个TCP连接。

HTTP 1.1 改变了 HTTP 协议的语义,默认使用持久连接。换句话说,除非明确告知(通过

Connection: close

首部),否则服务器默认会保持TCP连接打开。如果你使用的是 HTTP 1.1,从技术上说不需要

Connection: Keep-Alive

首部,但很多客户端还是选择加上它,比如我们的浏览器在发起请求的时候,一般会默认帮我们带上

Connection: Keep-Alive

首部。

我们来看一下为什么持久连接对我们来说这么重要。

假设一个网页仅包含一个HTML文档及一个CSS样式文件,服务器响应这两个文件的时间分别为40ms及20ms,服务器和浏览者分别在哈尔滨和深圳,两者之间单向光纤延迟为28ms(假设的理想状态,实际会比这个要大)。

  1. 首先是获取HTML文档的请求过程:

HTML下载完毕后,TCP连接关闭。

  1. 其次,发起CSS资源的请求,再次经历一次TCP握手

可以看到,两个HTTP请求都分别需要经历一次TCP的三次握手时间,另外,图中没有体现到的是,每一次TCP请求都有可能会经历一次TCP慢启动 过程,这是影响传播性能的一个不可忽视的重要因素。

假如我们底层的TCP连接得到重用,这时候的情况会是这样子:

很明显,在获取CSS的请求中,减少了一次握手往返。

一开始,每个请求要用两个TCP连接,总延迟为284ms。在使用持久连接后,避免了一次握手往返,总延迟减少为228ms。这里面两次请求节省了56ms(一个RTT,Round-Trip Time)的时间

上面的例子还只是只有一个HTML和一个CSS的简单假设情况,而现实世界的web的HTTP请求数量比这个要多得多,在启用持久连接的情况下,N次请求节省的总延迟时间就是(N-1)×RTT。

现实情况中,延迟更高、请求更多,性能提升效果比这里还要高得多。事实上,网络延迟越高,请求越多,节省的时间就越多。实际应用中,这个节省的总时间可按秒来算了。如果每一个HTTP都重启一个TCP连接,可想而知要浪费多少时间!

HTTP管道

持久 HTTP 可以让我们重用已有的连接来完成多次应用请求,但多次请求必须严格满足先进先出(FIFO,first in first out)的队列顺序:发送请求,等待响应完成,再发送客户端队列中的下一个请求。

举一下上一节持久连接的那个例子,首先,服务器处理完第一次请求后,会发生了一次完整的往返:先是响应回传,接着是第二次请求,在第二次请求到达服务器之间的这段时间里,服务器空闲。

如果服务器能在处理完第一次请求后,立即开始处理第二次请求呢?甚至,如果服务器可以并行处理两个请求呢?

这时候HTTP管道就派上用场了,HTTP管道是一个很小但对上述工作流非常重要的一次优化。

有了HTTP管道,我们的HTTP请求在一定程度上不用再一个一个地串行请求,而是可以多个并行了,看起来好像很理想:

如上图,HTML和CSS的请求同时到达服务器,服务器同时处理,然后返回。

这一次,通过使用HTTP管道,又减少了两次请求之间的一次往返,总延迟减少为 172 ms。从一开始没有持久连接、没有管道的284ms,到优化后的172ms,这40%的性能提升完全拜简单的协议优化所赐。

等一下,刚刚那个例子好像哪里还不够好:既然请求同时到达,同时处理,为什么后面要先返回HTML,然后再返回CSS?两者不能同时返回吗?

理想很丰满,现实却有点骨感,这就是HTTP 1.1管道的一个很大的局限性:HTTP请求无法很好地利用多路复用,不允许一个连接上的多个响应数据交错返回(多路复用)。因而一个响应必须完全返回后,下一个响应才会开始传输。

这个管道只是让我们把FIFO队列从客户端迁移到了服务器。也就是说,请求可以同时到达服务器,服务器也可以同时处理两个文件,但是,两个文件还是得按顺序返回给用户,如下图:

  • HTML和CSS请求同时到达,但先处理的是HTML请求
  • 服务器并行处理两个请求,其中处理 HTML 用时40ms,处理CSS用时20ms
  • CSS请求先处理完成,但被缓冲起来以等候HTML响应先发送
  • 发送完HTML响应后,再发送服务器缓冲中的CSS响应

可以看到,即使客户端同时发送了两个请求,而且CSS资源先准备就绪,但是服务器也会先发送 HTML 响应,然后再交付 CSS。

题外话 上面两节举的例子,说到了HTML和CSS请求同时到达,这是书中的例子,实际上,个人觉得这个例子举得不是很恰当。 实际的web中,HTML及其包含的CSS一般不会同时到达服务器,正常的瀑布图也不是这样的,往往是要先获取HTML内容后浏览器才能发起其中的CSS等资源请求。我想作者只是为了阐述原理吧,个人认为换成同一个HTML文档中CSS和JS可能更加恰当。

这个问题的原理在于TCP层面的“队首阻塞”,感兴趣可以去复习下计算机网络的课程。其代价往往是:不能充分利用网络连接,造成服务器缓冲开销,有可能导致客户端更大的延迟。更严重的时,假如前面的请求无限期挂起,或者要花很长时间才能处理完,所有后续的请求都将被阻塞,等待它完成。

所以,在HTTP 1.1中,管道技术的应用非常有限,尽管其优点毋庸置疑。实际上,一些支持管道的浏览器,通常都将其作为一个高级配置选项,但大多数浏览器都会禁用它。换句话说,作为前端工程师,开发的应用是面向普通浏览器应用的话,还是不要过多的指望HTTP管道,看来还是期待一下HTTP 2.0中对管道的优化吧。

不过,实际上还是有很好地利用HTTP管道的一些应用,例如在WWDC 2012上,有苹果的工程师分享了一个针对HTTP优化取得巨大成效的案例:通过使用HTTP的持久连接和管道,重用iTunes中既有的TCP连接,使得低网速用户的性能提升到原来的3倍!

实际上假如你想充分利用管道的好处,必须要保证下面这几点条件:

  • HTTP客户端支持管道
  • HTTP服务器支持管道
  • 应用可以处理中断的连接并恢复
  • 应用可以处理中断请求的幂等问题
  • 应用可以保护自身不受出问题的代理的影响

因为iTunes的服务器和客户端都受开发者控制的应用,所以他们能满足以上的条件。这也许能给开发hybrid应用或者开发浏览器之外的web应用的前端工程师们一些启发,如果你开发的网站面向的用户是使用五花八门的浏览器,你可能就没辙了。

使用多个TCP连接

因为HTTP 1.1管道存在上面的缺点,所以利用率不高。那么问题来了:假设没有使用HTTP管道,我们的所有HTTP请求都只能通过持久连接,一个接一个地串行返回,这得有多慢?

实际上,现阶段的浏览器厂商采取了另外的办法来解决HTTP 1.1管道的缺陷:允许我们并行打开多个TCP会话。至于是多少个,大家可能已经似曾相识:4到8个不等。这就是前端工程师非常熟悉的

浏览器只允许从同一个服务器并行加载4到8个资源

这一认识的真正来历。

HTTP持久连接虽然帮我们解决了TCP连接复用的问题,但是现阶段的HTTP管道却无法实现多个请求结果的交错返回,所以浏览器只能开启多个TCP连接,以达到并行地加载资源的目的。

只能说,这是作为绕过应用协议(HTTP)限制的一个权宜之计。可以这样打一个比喻,一个水管无法同时运输多种液体,那就只能给每一种液体开通一条运输管了,至于这个水管什么时候可以智能化到同时运输不同的液体,又能保证各自完整不受干扰到达目的地并在目的地自行分类?还是那一句,期待HTTP 2.0吧。

这里的连接数为什么是4到8个,是多方平衡的结果:这个数字越大,客户端和服务器的资源占用越多(在高并发访问的服务器中因为TCP连接造成的系统开销不可忽视),每个主机4到8个连接只不过是大家都觉得比较安全的一个数字。

域名分区

前面说到,浏览器和服务器之间只能并发4到8个TCP连接,也就是同时下载4到8个资源,够吗?

看看我们现在的大部分网站,动不动就几十个JS、CSS,一次六个,会造成后面大量的资源排队等待;另外,只下载6个资源,对带宽的利用率也是很低的。

打个比喻,一个工厂装了100根水管,每次却只能用其中6根接水,既慢,又浪费水管!

所以,我们前端性能优化中有一个最佳实践:使用域名分区

对啊,何必把自己只限制在一个主机上呢?我们可以手工将所有资源分散到多个子域名,由于主机名称不一样了,就可以突破浏览器的连接限制,实现更高的并行能力。

通过这种方式“欺骗”浏览器,这样浏览器和服务器之间的并行传输数量就变多了。

域名分区使用得越多,并行能力就越强!

但是,域名分区也是有代价的!

实践中,域名分区经常会被滥用。

例如,假设你的应用面向的是2G网络的手机用户,你分配了好几个域名,同时加载十几二十多个CSS、JS,这里的问题在于:

  • 每一个域名都会多出来的DNS查询开销,这是额外的机器资源开销和额外的网络延时代价。2G网络的DNS查询可不像你公司的电脑一样,相反可能是好几秒的延迟
  • 同时加载多个资源,以2G网络那种小得可怜的带宽来看,后果往往就是带宽被占满,每一个资源都下载得很慢
  • 手机的耗电加快

所以在一些低带宽高延时的场景,例如2G手机网络,域名分区做过了的话,不光不会带来前端性能的提升,反而会变成性能杀手。

域名分区是一种合理但又不完美的优化手段,最合适的办法就是,从最小分区数目(不分区)开始,然后逐个增加分区并度量分区后对应用的影响,从而得到一个最优的域名数。

连接与拼合

我们前端性能优化中有这么一个所谓的最佳实践原则:合并打包JS、CSS文件,以及做CSS sprite。

现在我们应该知道为什么要这样做了,实际上就是因为现在HTTP 1.1的管道太弱了,这两种技术的效果就好像是隐式地启用了HTTP 管道:来自多个响应的数据前后相继地连接在一起,消除了额外的网络延迟。

实际上,就是把管道提高了一层,置入了应用中,也许到了HTTP 2.0时代,前端工程师就不用干这样的活了吧?(HTTP 2.0的内容下篇讲)

当然,连接拼合技术同样有代价的。

  • 例如CSS sprite,浏览器必须分析整个图片,即便实际上只显示了其中的一小块,也要始终把整个图片都保存在内存中。浏览器没有办法把不显示的部分从内存中剔除掉。
  • 再者,既然JS、CSS合并了,带来的一般就是体积的增大,在带宽有限的环境下(例如2G)下载时间就变长,一般导致的就是页面渲染时间延后等后果。因为JavaScript 和CSS 处理器都不允许递增式执行的,对于JavaScript 和CSS 的解析及执行,则要等到整个文件下载完毕。

打包文件到底多大合适呢?可惜的是,没有理想的大小。然而,谷歌PageSpeed团队的测试表明,30~50 KB(压缩后)是每个JavaScript 文件大小的合适范围:既大到了能够减少小文件带来的网络延迟,还能确保递增及分层式的执行。具体的结果可能会由于应用类型和脚本数量而有所不同。

资源内嵌

JavaScript 和CSS 代码, 通过适当的script 和style 块可以直接放在页面中,而图片甚至音频或PDF 文件,都可以通过数据URI(data:[mediatype][;base64],data)的方式嵌入到页面中。

上面的这种方式我们称为资源内嵌

嵌入资源是另一种非常流行的优化方法, 把资源嵌入文档可以减少请求的次数。尤其在2G网络等情况中,内嵌资源可以有效地减少多次请求带来的时延。可以参考这篇文章在2G中的一些实践。

当然,有缺点:

  • 内嵌方式的资源,不能被浏览器、CDN 或其他缓存代理作为单独的资源缓存。如果在多个页面中都嵌入同样的资源,那么这个资源将会随着每个页面的加载而被加载,从而增大每个页面的总体大小。
  • 如果嵌入资源更新,那么所有以前出现过它的页面都将被宣告无效,而由客户端重新从服 务器获取。
  • 图片等非文本性资源通过base64 编码,会导致开销明显增大:编码后的资源大小比原大小增大33%!

Google的砖家给出一些经验:

  • 只考虑嵌入1~2 KB 以下的资源,因为小于这个标准的资源经常会导致比它自身更高的HTTP 开销
  • 如果文件很小,而且只有个别页面使用,可以考虑嵌入。理想情况下,最好是只用一次的资源
  • 如果文件很小,但需要在多个页面中重用,应该考虑集中打包
  • 如果小文件经常需要更新,就不要嵌入了
  • 通过减少 HTTP cookie 的大小将协议开销最小化

小结

本文介绍了HTTP 1.1在前端性能优化中的一些应用,有些是为了绕过HTTP 1.1局限性的一些不得不做的事情,比如资源合并、压缩、内嵌等,这些都可以说是HTTP 2.0来临前的一些解决问题的“黑魔法”。

HTTP 1.1及其利用当然远远没有本文说得那么简单,我只是浓缩了一部分内容,有兴趣可以去研究《HTTP权威指南》。

问答
BDD框架的前端如何搭建?
相关阅读
全面进阶 H5 直播(上)
NodeJs内存管理
WebGL 纹理颜色原理
【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识

此文已由作者授权腾讯云 社区发布,更多原文请点击

搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包!

海量技术实践经验,尽在云加社区!

本文转载于:猿2048https://www.mk2048.com/blog/blog.php?id=hkckhj&title=自从我这样撸代码以后,公司网页的浏览量提高了107%!

自从我这样撸代码以后,公司网页的浏览量提高了107%!相关推荐

  1. 网页首页浏览量计数器

    [.NET]独家发布网页首页浏览量计数器,目前网上木有我这么简单的 设计的思路就是在本地路径下放一个txt存放初始值,然后每次刷新首页之后让.net去访问这个txt文件读取这个初始值并累加之后再写入这 ...

  2. 什么是pv?如何计算公司每天的浏览量?

    PV(page view):即页面浏览量,或点击量,PV 是网站分析的一个术语,用以衡量网站用户 访问的网页的数量.一般来说,PV 与来访者的数量成正比,但是 PV 并不直接决定页面的真 实来访者数量 ...

  3. python爬虫新闻网页的浏览量转载量,Python爬取新闻网标题、日期、点击量

    最近接触Python爬虫,以爬取学校新闻网新闻标题.日期.点击量为例,记录一下工作进度 目前,感觉Python爬虫的过程无非两步: Step1.获取网页url(利用Python库函数import ur ...

  4. 怎么制作公司网页教程【网站制作】

    目录 怎么制作公司网页教程是什么? 1.了解自己制作公司网页的需求(分类刚需和次需) 2.确认本次制作公司网页需求和预算,找合适的第三方企业网站建设公司 3.确定制作公司网页的设计方案 4.结合制作公 ...

  5. HTML5期末大作业:茶叶主题网页设计——精美自适应绿色茶叶公司网页设计(12页) HTML+CSS+JavaScript

    HTML5期末大作业:茶叶主题网页设计--精美自适应绿色茶叶公司网页设计(12页) HTML+CSS+JavaScript 期末作业HTML代码 学生网页课程设计期末作业下载 web网页设计制作成品 ...

  6. HTML5期末大作业:淘宝网站设计——仿2021淘宝首页(1页) 大学生网页制作教程 表格布局网页模板 学生HTML静态水网页设计作业成品 简单网页制作代码 学生商城网页作品免费设计

    HTML5期末大作业:淘宝网站设计--仿2021淘宝首页(1页) 大学生网页制作教程 表格布局网页模板 学生HTML静态水网页设计作业成品 简单网页制作代码 学生商城网页作品免费设计 常见网页设计作业 ...

  7. HTML+CSS网页设计期末课程大作——体育篮球(5页面)大学生体育运动网页设计模板代码 校园篮球网页作业成品

    HTML+CSS网页设计期末课程大作--体育篮球(5页面)大学生体育运动网页设计模板代码 校园篮球网页作业成品 常见网页设计作业题材有 个人. 美食. 公司. 学校. 旅游. 电商. 宠物. 电器. ...

  8. 台湾老哥在深圳撸代码是怎么样的体验

    往期热门文章: 1.<往期精选优秀博文都在这里了!> 2.40张图看懂分布式追踪系统原理及实践 3.阿里终面:分布式事务原理 4.为什么在系统中不推荐双写? 5.Thread.sleep( ...

  9. 撸代码速度提升10倍的技巧,收藏慢慢看!!!【内含福利】

    今天带大家提升一下写代码的速度,idea 是我们用的最多的开发工具,这个工具有个特别的牛逼的功能:live template. 这个功能掌握之后,撸代码的速度至少翻两番. 先带大家见识一下这玩意的威力 ...

最新文章

  1. 学习Cassandra资料的一些整理
  2. 关于matlab中princomp的使用说明讲解
  3. ACL 2020 | 多编码器是否能够捕获篇章级信息?
  4. linux下面的查找
  5. Servlet中防止盗链的代码
  6. rose怎么把两个mdl弄在一起_面试美敦力,HR要我降Title,怎么办?(上)
  7. mysql 在线日期_mysql,由 时间点求时间段的问题,在线时间率
  8. 并行算法设计与性能优化_MySQL高性能优化规范建议,从设计,命名,开发等一条线的建议...
  9. 二叉查找树--插入、删除、查找
  10. 什么时候用到id和class?
  11. 高通msm8953平台摄像头移植
  12. Linux自定义日志文件设置回滚(避免信息溢出)
  13. Kafka Sql:简单使用
  14. quartz 每月一次_Quartz 定时任务框架详解
  15. 前端实现网图转base64
  16. 九州量子黄蕾蕾:我们是冲着量子通信产业化来的
  17. 第二阶段--团队冲刺--第四天
  18. 钢琴的乐理知识以及musicXml属性介绍
  19. Linux内核分析2:一个简单的时间片轮转多道程序内核代码分析
  20. rf中resourceid_RF(三)元素定位方法

热门文章

  1. python利用自动识别写模块_序章:资料预处理(python3.6 可用fortran unformatted sequencial data读取模块)...
  2. 问题 1045: [编程入门]自定义函数之整数处理
  3. volatile、static
  4. Block(Closure) Tips
  5. 关于excel中的查找
  6. 15 个最新的 CSS3 教程
  7. Eigen(6)快操作
  8. Python函数参数传递:传值还是传引用
  9. 设置过mysql远程连接后仍然无法进行远程连接 (mysql mysql报错2003 can't connect)
  10. 上传文件ajax,ajax 文件上传