关于HTTP的Connection
- HTTP的请求是在TCP的链接上发送的
- TCP的链接又分为长连接,短链接
- HTTP的请求要先去创建一个TCP的链接
- 然后在TCP的链接上将HTTP的请求发送并且接受完返回
- 这时候一次HTTP请求已经结束了,浏览器和服务端就会考虑是否关闭这个TCP链接
- 如果不关闭,这个TCP链接就会一直开着,就会有一定的消耗
- 如果接下去还有请求,可以直接在这个TCP链接上发送,就不需要进行三次握手来创建链接的消耗
- 如果直接关闭,代表了下次请求的时候,又要去重新创建链接,这就会有一个网络延迟的开销,但会减少客户端和服务端链接的并发数
- 但是实际使用中,每次创建链接并关闭这种策略的话,会影响效率,实际的网站并发量比较大,这样实际的开销会远远超过保持长连接的策略
- 实际上,长链接可以设置链接的超时功能Timeout(过了一段时间没有请求会自动关闭), 所以保持长连接才是最好的策略
- 举个实际的例子
- 打开百度网站,浏览器打开控制台,切换到Network选项中,勾选上Disable cache
- 刷新页面,在All次级选项页面上所有资源列表中右键勾选上Connection ID这一项,在列表中就会多出现一项Connection ID
- 这个Connection ID就代表了TCP链接的ID,这样我们就可以区分是否是同一个链接
- 我们可以看到这个这个Connection ID列中有很多资源使用了相同的ID, 在不同的域下使用不同的ID, 同域下尽量复用这些链接ID
- 在HTTP1.1的TCP链接其发送请求的策略是有先后顺序的,比如有10个请求是不可以并发的在一个TCP链接上去发送
- 在一个TCP链接上只能一个接着一个的发送,而我们希望网站在加载首页的时候,能够并发进行,这样会提高效率
- 这时候,浏览器允许并发的创建TCP链接,Chrome允许的是6个并发TCP的链接数量
- 所以,在加载首页的时候,会使用6个并发TCP链接, 全部使用完成之后才能继续进行并发
- 比如有10个要进行并发,会先进行6个并发的创建,在这6个中,至少有一个完成,才能继续依次进行
- 如何保证浏览器创建的是长连接而非短链接呢
- 点击任意一个连接,在响应头上的头信息中,一般会有
Connection: Keep-Alive - 这就代表链接是被保持的,就代表请求不会一下子被关闭
- 在请求头的头信息中,也一般有一个
Connection: Keep-Alive - 这里有一个协商的过程,在发送请求的时候,浏览器是希望服务端是保持长链接的
- 如果服务端选择不保持,浏览器端还是会选择关闭掉
- 点击任意一个连接,在响应头上的头信息中,一般会有
程序示例
-
test.html
<img src='/test1.jpg'> <img src='/test2.jpg'> <img src='/test3.jpg'> <img src='/test4.jpg'> <img src='/test5.jpg'> <img src='/test6.jpg'> <img src='/test7.jpg'> -
server.js
const http = require('http'); const fs = require('fs'); http.createServer((req, res) => { console.log('req come: ', req.url); if(req.url === '/') { const html = fs.readFileSync('test.html', 'utf8'); // 默认是下面这个writeHead设置,不写也可以 res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(html); } else { // 此处显示图片 const img = fs.readFileSync('test.jpg'); res.writeHead(200, { 'Content-Type': 'image/jpg' }); res.end(img); } }).listen(8000, () => { console.log('server is running on port 8000'); }); -
随便准备一张图片:test.jpg,启动程序 $
node server.js -
访问:http://localhost:8000/
-
将浏览器模拟网络调整为较慢速的网络,设置Online -> Fast 3G
-
打开浏览器Network中的Connection ID
-
刷新页面,可以看到除了html页面的加载和第一张图片复用了一个ID
-
其他的5张图片都是不同的Connection ID,说明浏览器进行了6个并发请求
-
然后从Waterfall列(网络分时请求)中可见第7张图片是要等待的
-
等待请求传输完成后发现它复用了第一张图片的Connection ID
-
这就是TCP的并发
-
我们可以把长连接修改成短链接,修改程序示例:
const http = require('http'); const fs = require('fs'); http.createServer((req, res) => { console.log('req come: ', req.url); if(req.url === '/') { const html = fs.readFileSync('test.html', 'utf8'); res.writeHead(200, { 'Content-Type': 'text/html', 'Connection': 'close' // 添加这行 }); res.end(html); } else { // 此处显示图片 const img = fs.readFileSync('test.jpg'); res.writeHead(200, { 'Content-Type': 'image/jpg', 'Connection': 'close' // 添加这行 }); res.end(img); } }).listen(8000, () => { console.log('server is running on port 8000'); }); -
重启程序并刷新浏览器后可发现,每一个Connection ID都是不同的,而且ID序号递增
-
这就是没有重复利用TCP的链接,每次请求后链接就会被关闭
-
我们在开发服务器时,可以合理利用这个
Connection: Keep-Alive -
可以给当前TCP链接设置一个自动关闭的时间,这是服务端的设置和HTTP协议没有太大关系
-
在HTTP2版本中, 有了一个信道复用的概念, 在TCP链接上可以并发的发送HTTP请求
-
这表示着我们在访问网站时,可以使用一个TCP链接就可以了,这样就可以极大的降低开销
-
可以打开谷歌网站查看HTTP2版本的使用,在同域下基本都是使用同一个Connection ID
-
此时,开销会被降至最低,而且速度有一个本质的提升
-
同时HTTP2有服务端自动推送的功能,此处不再赘述
本文介绍了HTTP协议中的长连接和短连接概念,以及它们在网络请求中的应用。通过示例解释了如何通过设置'Connection: Keep-Alive'来维持长连接,以实现TCP链接的复用,提高效率。同时讨论了HTTP1.1的并发限制和HTTP2的信道复用技术,说明了长连接在降低开销和提升速度上的优势。
2544

被折叠的 条评论
为什么被折叠?



