Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >我的 HTTP/1.1 好慢啊!

我的 HTTP/1.1 好慢啊!

作者头像
小林coding
发布于 2021-03-15 08:18:58
发布于 2021-03-15 08:18:58
67700
代码可运行
举报
文章被收录于专栏:小林coding小林coding
运行总次数:0
代码可运行

问你一句:「你知道 HTTP/1.1 该如何优化吗?

我想你第一时间想到的是,使用 KeepAlive 将 HTTP/1.1 从短连接改成长链接。

这个确实是一个优化的手段,它是从底层的传输层这一方向入手的,通过减少 TCP 连接建立和断开的次数,来减少了网络传输的延迟,从而提高 HTTP/1.1 协议的传输效率。

但其实还可以从其他方向来优化 HTTP/1.1 协议,比如有如下 3 种优化思路:

  • 尽量避免发送 HTTP 请求
  • 在需要发送 HTTP 请求时,考虑如何减少请求次数
  • 减少服务器的 HTTP 响应的数据大小

下面,就针对这三种思路具体看看有哪些优化方法。


1 如何避免发送 HTTP 请求?

这个思路你看到是不是觉得很奇怪,不发送 HTTP 请求,那还客户端还怎么和服务器交互数据?小林你这不是耍流氓嘛?

冷静冷静,你说的没错,客户端当然要向服务器发送请求的。

但是,对于一些具有重复性的 HTTP 请求,比如每次请求得到的数据都一样的,我们可以把这对「请求-响应」的数据都缓存在本地,那么下次就直接读取本地的数据,不必在通过网络获取服务器的响应了,这样的话 HTTP/1.1 的性能肯定肉眼可见的提升。

所以,避免发送 HTTP 请求的方法就是通过缓存技术,HTTP 设计者早在之前就考虑到了这点,因此 HTTP 协议的头部有不少是针对缓存的字段。

那缓存是如何做到的呢?

客户端会把第一次请求以及响应的数据保存在本地磁盘上,其中将请求的 URL 作为 key,而响应作为 value,两者形成映射关系。

这样当后续发起相同的请求时,就可以先在本地磁盘上通过 key 查到对应的 value,也就是响应,如果找到了,就直接从本地读取该响应。毋庸置疑,读取本次磁盘的速度肯定比网络请求快得多,如下图:

聪明的你可能想到了,万一缓存的响应不是最新的,而客户端并不知情,那么该怎么办呢?

放心,这个问题 HTTP 设计者早已考虑到。

所以,服务器在发送 HTTP 响应时,会估算一个过期的时间,并把这个信息放到响应头部中,这样客户端在查看响应头部的信息时,一旦发现缓存的响应是过期的,则就会重新发送网络请求。HTTP 关于缓说明会的头部字段很多,这部分内容留在下次文章,这次暂时不具体说明。

如果客户端从第一次请求得到的响应头部中发现该响应过期了,客户端重新发送请求,假设服务器上的资源并没有变更,还是老样子,那么你觉得还要在服务器的响应带上这个资源吗?

很显然不带的话,可以提高 HTTP 协议的性能,那具体如何做到呢?

只需要客户端在重新发送请求时,在请求的 Etag 头部带上第一次请求的响应头部中的摘要,这个摘要是唯一标识响应的资源,当服务器收到请求后,会将本地资源的摘要与请求中的摘要做个比较。

如果不同,那么说明客户端的缓存已经没有价值,服务器在响应中带上最新的资源。

如果相同,说明客户端的缓存还是可以继续使用的,那么服务器仅返回不含有包体的 304 Not Modified 响应,告诉客户端仍然有效,这样就可以减少响应资源在网络中传输的延时,如下图:

缓存真的是性能优化的一把万能钥匙,小到 CPU Cache、Page Cache、Redis Cache,大到 HTTP 协议的缓存。


2 如何减少 HTTP 请求次数?

减少 HTTP 请求次数自然也就提升了 HTTP 性能,可以从这 3 个方面入手:

  • 减少重定向请求次数
  • 合并请求
  • 延迟发送请求
2.1 减少重定向请求次数

我们先来看看什么是重定向请求

服务器上的一个资源可能由于迁移、维护等原因从 url1 移至 url2 后,而客户端不知情,它还是继续请求 url1,这时服务器不能粗暴地返回错误,而是通过 302 响应码和 Location 头部,告诉客户端该资源已经迁移至 url2 了,于是客户端需要再发送 url2 请求以获得服务器的资源。

那么,如果重定向请求越多,那么客户端就要多次发起 HTTP 请求,每一次的 HTTP 请求都得经过网络,这无疑会越降低网络性能。

另外,服务端这一方往往不只有一台服务器,比如源服务器上一级是代理服务器,然后代理服务器才与客户端通信,这时客户端重定向就会导致客户端与代理服务器之间需要 2 次消息传递,如下图:

如果重定向的工作交由代理服务器完成,就能减少 HTTP 请求次数了,如下图:

而且当代理服务器知晓了重定向规则后,可以进一步减少消息传递次数,如下图:

除了 302 重定向响应码,还有其他一些重定向的响应码,你可以从下图看到:

其中,301308 响应码是告诉客户端可以将重定向响应缓存到本地磁盘,之后客户端就自动用 url2 替代 url1 访问服务器的资源。

2.2 合并请求

如果把多个访问小文件的请求合并成一个大的请求,虽然传输的总资源还是一样,但是减少请求,也就意味着减少了重复发送的 HTTP 头部

另外由于 HTTP/1.1 是请求响应模型,如果第一个发送的请求,未收到对应的响应,那么后续的请求就不会发送,于是为了防止单个请求的阻塞,所以一般浏览器会同时发起 5-6 个请求,每一个请求都是不同的 TCP 连接,那么如果合并了请求,也就会减少 TCP 连接的数量,因而省去了 TCP 握手和慢启动过程耗费的时间

接下来,具体看看合并请求的几种方式。

有的网页会含有很多小图片、小图标,有多少个小图片,客户端就要发起多少次请求。那么对于这些小图片,我们可以考虑使用 CSS Image Sprites 技术把它们合成一个大图片,这样浏览器就可以用一次请求获得一个大图片,然后再根据 CSS 数据把大图片切割成多张小图片。

图来源于:墨染枫林的CSDN

这种方式就是通过将多个小图片合并成一个大图片来减少 HTTP 请求的次数,以减少 HTTP 请求的次数,从而减少网络的开销

除了将小图片合并成大图片的方式,还有服务端使用 webpack 等打包工具将 js、css 等资源合并打包成大文件,也是能达到类似的效果。

另外,还可以将图片的二进制数据用 base64 编码后,以 URL 的形式潜入到 HTML 文件,跟随 HTML 文件一并发送.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<image src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPoAAAFKCAIAAAC7M9WrAAAACXBIWXMAA ... />

这样客户端收到 HTML 后,就可以直接解码出数据,然后直接显示图片,就不用再发起图片相关的请求,这样便减少了请求的次数。

图来源于:陈健平的CSDN

可以看到,合并请求的方式就是合并资源,以一个大资源的请求替换多个小资源的请求

但是这样的合并请求会带来新的问题,当大资源中的某一个小资源发生变化后,客户端必须重新下载整个完整的大资源文件,这显然带来了额外的网络消耗。

2.3 延迟发送请求

不要一口气吃成大胖子,一般 HTML 里会含有很多 HTTP 的 URL,当前不需要的资源,我们没必要也获取过来,于是可以通过「按需获取」的方式,来减少第一时间的 HTTP 请求次数。

请求网页的时候,没必要把全部资源都获取到,而是只获取当前用户所看到的页面资源,当用户向下滑动页面的时候,再向服务器获取接下来的资源,这样就达到了延迟发送请求的效果。


3 如何减少 HTTP 响应的数据大小?

对于 HTTP 的请求和响应,通常 HTTP 的响应的数据大小会比较大,也就是服务器返回的资源会比较大。

于是,我们可以考虑对响应的资源进行压缩,这样就可以减少响应的数据大小,从而提高网络传输的效率。

压缩的方式一般分为 2 种,分别是:

  • 无损压缩
  • 有损压缩
3.1 无损压缩

无损压缩是指资源经过压缩后,信息不被破坏,还能完全恢复到压缩前的原样,适合用在文本文件、程序可执行文件、程序源代码。

首先,我们针对代码的语法规则进行压缩,因为通常代码文件都有很多换行符或者空格,这些是为了帮助程序员更好的阅读,但是机器执行时并不要这些符,把这些多余的符号给去除掉。

接下来,就是无损压缩了,需要对原始资源建立统计模型,利用这个统计模型,将常出现的数据用较短的二进制比特序列表示,将不常出现的数据用较长的二进制比特序列表示,生成二进制比特序列一般是「霍夫曼编码」算法。

gzip 就是比较常见的无损压缩。客户端支持的压缩算法,会在 HTTP 请求中通过头部中的 Accept-Encoding 字段告诉服务器:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Accept-Encoding: gzip, deflate, br

服务器收到后,会从中选择一个服务器支持的或者合适的压缩算法,然后使用此压缩算法对响应资源进行压缩,最后通过响应头部中的 content-encoding 字段告诉客户端该资源使用的压缩算法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
content-encoding: gzip

gzip 的压缩效率相比 Google 推出的 Brotli 算法还是差点意思,也就是上文中的 br,所以如果可以,服务器应该选择压缩效率更高的 br 压缩算法。

3.2 有损压缩

与无损压缩相对的就是有损压缩,经过此方法压缩,解压的数据会与原始数据不同但是非常接近。

有损压缩主要将次要的数据舍弃,牺牲一些质量来减少数据量、提高压缩比,这种方法经常用于压缩多媒体数据,比如音频、视频、图片。

可以通过 HTTP 请求头部中的 Accept 字段里的「 q 质量因子」,告诉服务器期望的资源质量。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Accept: audio/*; q=0.2, audio/basic

关于图片的压缩,目前压缩比较高的是 Google 推出的 WebP 格式,它与常见的 Png 格式图片的压缩比例对比如下图:

来源于:https://isparta.github.io/compare-webp/index.html

可以发现,相同图片质量下,WebP 格式的图片大小都比 Png 格式的图片小,所以对于大量图片的网站,可以考虑使用 WebP 格式的图片,这将大幅度提升网络传输的性能。

关于音视频的压缩,音视频主要是动态的,每个帧都有时序的关系,通常时间连续的帧之间的变化是很小的。

比如,一个在看书的视频,画面通常只有人物的手和书桌上的书是会有变化的,而其他地方通常都是静态的,于是只需要在一个静态的关键帧,使用增量数据来表达后续的帧,这样便减少了很多数据,提高了网络传输的性能。对于视频常见的编码格式有 H264、H265 等,音频常见的编码格式有 AAC、AC3。


总结

这次主要从 3 个方面介绍了优化 HTTP/1.1 协议的思路。

第一个思路是,通过缓存技术来避免发送 HTTP 请求。客户端收到第一个请求的响应后,可以将其缓存在本地磁盘,下次请求的时候,如果缓存没过期,就直接读取本地缓存的响应数据。如果缓存过期,客户端发送请求的时候带上响应数据的摘要,服务器比对后发现资源没有变化,就发出不带包体的 304 响应,告诉客户端缓存的响应仍然有效。

第二个思路是,减少 HTTP 请求的次数,有以下的方法:

  1. 将原本由客户端处理的重定向请求,交给代理服务器处理,这样可以减少重定向请求的次数;
  2. 将多个小资源合并成一个大资源再传输,能够减少 HTTP 请求次数以及 头部的重复传输,再来减少 TCP 连接数量,进而省去 TCP 握手和慢启动的网络消耗;
  3. 按需访问资源,只访问当前用户看得到/用得到的资源,当客户往下滑动,再访问接下来的资源,以此达到延迟请求,也就减少了同一时间的 HTTP 请求次数。

第三思路是,通过压缩响应资源,降低传输资源的大小,从而提高传输效率,所以应当选择更优秀的压缩算法。

不管怎么优化 HTTP/1.1 协议都是有限的,不然也不会出现 HTTP/2 和 HTTP/3 协议,后续我们再来介绍 HTTP/2 和 HTTP/3 协议。

好了,此次分享到这就结束了,如果这篇文章对你有帮助,欢迎来个三连,你们的支持就是小林的最大动力,我们下次见!


巨人的肩膀
  1. https://isparta.github.io/compare-webp/index.html
  2. https://zh.wikipedia.org/wiki/https://en.wikipedia.org/wiki/Lossy_compression
  3. https://en.wikipedia.org/wiki/Lossless_compression
  4. https://time.geekbang.org/column/article/242667
  5. https://www.tutorialrepublic.com/css-tutorial/css-sprites.php
  6. https://blog.csdn.net/weixin_38055381/article/details/81504716
  7. https://blog.csdn.net/weixin_44151887/article/details/106278559
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-02-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小林coding 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
编辑精选文章
换一批
HTTP/1.1任你有万般不好,但我也要好好待你
答案就是缓存。我们通过将HTTP响应的数据缓存到本地,下次请求时直接从本地磁盘读取,避免网络IO的耗时。
shysh95
2021/11/16
3280
应用层编解码调优思路——HTTP1.1和HTTP2以及编解码工具Protobuf
在上一篇中和大家分享了HTTPS协议的优化,这一篇我们先从一道被各厂面试官考烂的面试题“从浏览器输入地址到呈现页面中间发生了什么,结合通信协议”出发,开始谈谈HTTP1.1和HTTP/2,简单介绍编解码工具Protobuf并从多角度提供上述技术的优化思路。给你5分钟先思考下这道题,计时开始……
才浅Coding攻略
2022/12/12
5370
应用层编解码调优思路——HTTP1.1和HTTP2以及编解码工具Protobuf
跟我一起探索 HTTP-HTTP 协议中的数据压缩
数据压缩是提高 Web 站点性能的一种重要手段。对于有些文件来说,高达 70% 的压缩比率可以大大减低对于带宽的需求。随着时间的推移,压缩算法的效率也越来越高,同时也有新的压缩算法被发明出来,应用在客户端与服务器端。
用户1418987
2023/10/16
3130
跟我一起探索 HTTP-HTTP 协议中的数据压缩
前端性能优化指南——网络篇
网络,在我们开发的页面的访问过程中,是最开始的一个环节,同时,也是一个非常重要的环节。 当我们在提及网络优化的时候,我们都会说些什么呢。 事实上来讲,如果可以话的,我们对于 IDC,ISP,CDN,BGP,TDO 的优化应该作用是非常明显的。但是一般来讲,这些服务的优化很少可以被前端影响。所以这次就提一下,暂时不做详细的描述。当然了,对我们来说,及时监控不同服务商和各地节点的网络问题也是非常重要的。 那么接下来呢。说到网络性能优化,我们能做的事情主要是这两部分。 对协议本身进行优化 对传输的资源进行优化 我
企鹅号小编
2018/01/26
8800
HTTP/2:让网络飞起来
今天我们来聊聊一个让网络飞起来的技术——HTTP/2。你可能已经听说过 HTTP/2,但是你知道它是什么吗?为什么我们需要它?它和我们正在使用的 HTTP/1.1 有什么区别?别急,接下来我们将一一揭晓。
陆业聪
2024/08/08
2550
HTTP/2:让网络飞起来
《透视http协议》笔记
客户端向服务器发送请求,服务器会拼出一个响应报文发回客户端,而状态码就存在于这个响应报文里
素履coder
2022/02/17
5330
《透视http协议》笔记
【HTTP】Http协议理解
关于http(中文名:超文本传输协议),你无须明白那冗长的理论解释,只需要明白3点:
前端修罗场
2023/10/07
4180
【HTTP】Http协议理解
HTTP 常见面试题速查
PUT 和 PATCH 都是更新资源,而 PATCH 用来对已知资源进行局部更新。如果发送修改信息是全量覆盖就是用 PUT, 如果只是部分修改则使用 PATCH。
Cellinlab
2023/05/17
3130
你必须懂的前端性能优化
对于 DNS 解析和 TCP 连接两个步骤,我们前端可以做的努力非常有限。相比之下,HTTP 连接这一层面的优化才是我们网络优化的核心。
张炳
2019/08/02
7390
你必须懂的前端性能优化
【优化】356- 你必须懂的前端性能优化
对于 DNS 解析和 TCP 连接两个步骤,我们前端可以做的努力非常有限。相比之下,HTTP 连接这一层面的优化才是我们网络优化的核心。
pingan8787
2019/09/24
6600
【优化】356- 你必须懂的前端性能优化
前端优化汇总,到底该不该做?
[本文由@IT·平头哥联盟-首席填坑官∙苏南 分享] 引言 大家好,这里是@IT·平头哥联盟,我是首席填坑官——苏南(South·Su),今天是国庆节的第二天,这个假期没有外出(不要问我为什么,自己脑补~😭),前些天分享了一篇前端面试汇总的文章,有些同学在群里问了其中的一些细节,其中大家最关心的性能优化这块,今天整理了公司项目中的一些认为不错的点,跟大家一起分享,如有理解错误,请纠正。 优化概括 1、首先最基本的,CSS样式表放在页面头部Head内且link链式引入,javascript放在底部body结束
苏南
2018/12/05
8080
前端优化汇总,到底该不该做?
HTTP协议
该版本只有一个命令GET;没有HEADER等描述数据的信息; 服务器发送完毕,就关闭TCP连接。
木可大大
2018/07/25
4020
HTTP协议
【黄啊码】什么是HTTP?HTTP是如何演变的?
超文本传输协议。HTTP是在计算机中用于两点之间传输文字、图片、音频、视频等超文本数据的约定和规范
黄啊码
2022/06/10
1.6K0
HTTP 报文
当客户端发出一个请求,服务器就会做出响应,返回一个响应报文。无论是请求报文还是响应报文都是由三部分组成:Line ,header,body。
Yif
2019/12/26
1.5K0
2023学习日志
redis是一个基于内存的键值对数据库,通常用作缓存数据库,减少对mysql等基于磁盘的数据库的访问次数,提高响应效率。
TomoriNao
2023/06/07
2520
【面经】 HTTP 基础知识
大家好,我是图图。也有一个多月没有写文章了。由于各种原因,被迫提桶,真是艰难。经过几轮的面试之后,被面试官虐得惨惨的,其中许多原因是没有仔细的学过 HTTP 的知识,我对这块的知识相对来说比较薄弱,所以决定把数据结构和算法得先放一放了。所以把 HTTP 的知识学一遍,然后再补一下JS的基础。
后端码匠
2021/05/10
7350
【面经】 HTTP 基础知识
《HTTP/2 基础教程》 阅读摘要
最近粗线了不少 HTTP2 相关的帖子和讨论,感觉新一轮的潮流在形成,所以最近找了本 HTTP2 相关书籍做知识储备,刚好记成笔记以备后询 ~
前端下午茶
2019/06/27
1.1K0
《HTTP/2 基础教程》 阅读摘要
TCP/IP协议族(二) HTTP报文头解析
本篇博客我们就来详细的聊一下HTTP协议的常用头部字段,当然我们将其分为请求头和响应头进行阐述。下方是报文头每个字段的格式,首先是头部字段的名称,如Accept,冒号后方紧跟的是该字段名所对应的值,每个值之间有逗号分隔。如果该值需要优先级,那么在值的后方跟上优先级q=0.8(q的值由0~1,优先级从低到高)。值与优先级中间由分号相隔。 头部字段名:值1, 值2;q=0.8 下方就是截取的网络请求中Request Headers的部分内容。红框中的Accept-Language就是头部字段名,冒号后边就是
lizelu
2018/01/11
1.4K0
TCP/IP协议族(二) HTTP报文头解析
《图解HTTP》大纲
URI(Uniform Resource Identifier) 统一资源标识符;URL(Uniform Resource Locator) 统一资源定位符。
三流之路
2018/09/11
9110
为你重新系统梳理下, Web 体验优化中和图有关的那些事(万字长文)
Web 页面性能优化,解决了图片相关,问题就解决了大半。本文从 Web 常见的图片格式入手,引出与图片优化相关的有效方案,期望对大家能有一点帮助。
lucifer210
2019/11/15
1.4K0
相关推荐
HTTP/1.1任你有万般不好,但我也要好好待你
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验