HTTP2概念和应用

HTTP2概念和应用

2020年10月16日

之前写的一点笔记,拿过来充个数


看完HTTP/2简介记笔记

HTTP/2

概念

即HTTP协议的版本2,简称h2。

简单历史

开始是Google家针对HTTP/1.x的优化操作,协议名为SPDY,后来因为性能提升明显,各大浏览器开始支持SPDY,然后一些大型网站也使用了SPDY。到15年SPDY演化为HTTP/2。

HTTP/2和HTTP/1.1的区别

1.数据传输方式

HTTP/1.1传输数据大致分两部分,header和body。其中header是纯文本,body则一般是文本或二进制流。
HTTP/2则采用二进制数据分帧的数据传输方式,针对一个请求的header和body,服务端将把它们分割为一个个的二进制帧,客户端(比如浏览器)收到之后再重组处理为header和body。

2.连接数

HTTP/1.1一个请求会建立一个连接,数据传输完毕之后关闭连接。一般浏览器最多支持同时开启6个连接(针对同一个域名,关键词同源)。于是如果同时发起了多个请求,那么浏览器会同时开启多个tcp连接。
HTTP/2则会建立一个连接(针对同一个域名),该域名下所有的请求包括资源文件都会通过上述提到的二进制帧的双向传输来完成。

3.HTTP/2的一些新特性

服务端推送: 例如服务端在客户端获取index.html的同时,向服务端推送index.js, 而不是在客户端解析了部分index.html的内容之后,发现需要加载index.js才开始向服务端请求该文件。如此进一步提升了页面加载速度。

嗯还有啥。这个先占个位

HTTP/2相比HTTP/1.1的优势

嗯全是优势没有劣质,往前几年的话,h2的劣势应该是兼容性。
主要优势

  1. 性能提升
  2. 省流量
  3. 优化上限的提升

这里先说省流量
HTTP/2对请求的header值做了压缩(之前的都是纯文本),并且还针对header的键(名字),做了静态表,初始为空,之后的请求对该表进行增量更新,于是实际上并不是每次请求都会把完整的header内容传输过去。另外对body的也是有压缩作用的(@二进制分帧)。

减少了数据传输的大小,那么文件加载的时间则会减少,于是体现在性能提升。另外HTTP/2的新特性服务器推送也对性能提升有贡献。

优化上限这里指相比之前HTTP/1.x的一些优化。
比如雪碧图,比如bundlejs(即将一些js糅合在一个文件一起加载),在h2中雪碧图已经没有必要,h2的数据传输方式有点像把所有请求糅进一个大大的雪碧图中。对于一些细碎的资源,也已经可以自己做单独的缓存无效化,这是雪碧图的方式所实现不了的。
再比如对同源请求最多同时开启6个的限制。h2不存在这个问题,http/1.x为了解决这个问题,会将资源域名用不同的域名分开,这样就可以绕开这个限制。

要不要优化

嗯。。。看数据量看访问量看业务需要,优化做到极致没多少人访问那也太寂寞了。
如果是折腾而已那自是另当别论。

具体怎么用HTTP/2

思路大概两种
代理服务器做h2支持
业务服务自己支持h2

代理服务器做h2支持

这里拿nginx来讲
client/browser <- h2 -> nginx <- http/1.x-> business server

这里h2必须使用https协议(嗯什么年代了还不支持https么)
nginx只需要配置
listen 443 ssl http2
即可
其他配置与以往没差

如果想使用server push功能,
则需要额外的配置, 最常用的应该是跟proxy_pass写在一起的
http2_push_preload on;
然后业务服务器只需要在对应的请求的header中写入特定的键值,nginx将会为你处理server push
详见nginx文档

业务服务器自己支持h2

因为h2要求在https协议之上,所以如果是业务服务器层面要支持h2,则需要支持https
这里给用node实现的代码
如果仅仅是开启h2就很简单,引入http2包调用createSecureServer即可
如果想要使用server push ,则需要自己写额外的代码逻辑了(下详)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const http2 = require('http2');
const serve = require('koa-static');

// 证书配置
const certOptions = {
key: fs.readFileSync('pathtossl/key.pem'),
cert: fs.readFileSync('pathtossl/cert.pem')
};
// server push
function push(ctx, filePath) {
const { fileDescriptor, headers } = getFile(filePath) //
const pushHeaders = { [HTTP2_HEADER_PATH]: filePath }
ctx.res.stream.pushStream(pushHeaders, (err, pushStream) => {
// 这里有坑,如果不过错误处理会导致服务挂掉,毕竟node。
// 其中一个挂掉的场景. 客户端在有缓存的情况下会使用缓存并拒绝接受server push
if (!err && !pushStream.destroyed)pushStream.respondWithFD(fileDescriptor, headers)
})
}

app.use(async (ctx, next) => {
const urlPath = ctx.request.path;
// 当请求首页的时候,把index.js和style.css也推给客户端
if (urlPath === '/index.html' || urlPath === '/') {
push(ctx, '/index.js'); // server push
push(ctx, '/style.css');
}
await next();
});
// 静态资源
app.use(serve(__dirname + '/static'));
http2.createSecureServer({
...certOptions,
allowHTTP1: true,
}, appCb).listen(3002);