为什么启用HTTP2后多个请求还是排队发送?
我给网站启用了HTTP/2,但发现同时发送的多个fetch请求还是在排队执行。比如同时请求三个图片资源,网络面板显示还是按顺序发送,这不应该是多路复用吗?
我用下面的代码测试的,服务器是Nginx 1.20配置了h2协议。难道是我的代码有问题?还是需要额外设置什么?
Promise.all([
fetch('/img1.jpg'),
fetch('/img2.jpg'),
fetch('/img3.jpg')
]).then(responses => {
console.log('所有请求完成', Date.now());
});
用浏览器开发者工具看,三个请求在时间轴上明显是串行发起的,而且连接复用的是同一个:443流标识。难道HTTP2的多路复用需要配合其他设置才能生效?
HTTP/2的多路复用确实允许在一个TCP连接上并行传输多个请求响应,但浏览器对不同类型的请求有各自的并发策略和优先级队列。你用fetch请求图片,虽然代码是Promise.all并行发出去的,但浏览器可能把它们归类为“低优先级”资源,而且fetch默认不参与浏览器的常规资源加载调度,导致底层还是被节流或串行化处理了。
关键点有几个:
1. fetch默认不会像img标签那样走浏览器内置的资源加载优化流程。如果你换成三个
new Image().src = '/imgx.jpg',大概率就能看到真正的并行请求,同一个HTTP/2连接上多路复用生效。2. 即使是HTTP/2,浏览器也会限制每个源的最大并发流数量(一般是100左右),但更重要的是,它会按资源类型分配优先级。脚本、样式通常优先级高,fetch获取的资源如果没有特别声明,容易被排后。
3. 确认Nginx真的启用了h2:看响应头有没有
http2,服务器返回的协议是不是h2。可以用curl -I --http2 https://yoursite.com验证。4. 另外注意,如果这些图片在同一域名下,且你没开子域名分片,那本来就在同一个连接复用,这是正常的。关键是看时间轴是不是真正重叠传输,而不是发起时间微小错开就以为是串行——开发者工具里的“Start Time”排序容易误导人,要看“Timing”里的真实网络活动区间。
建议你试一下把fetch换成
priority: 'high'(部分浏览器支持),再观察Network面板的流分布。你会发现HTTP/2其实在工作,只是fetch的行为和你预期的不太一样。说白了,不是HTTP/2没用,是fetch + 浏览器兼容调度的问题。
1. **浏览器的实现限制**:虽然 HTTP/2 支持多路复用,但有些浏览器可能会对同一时间发起的 fetch 请求做一定的优化或排队处理,尤其是在资源类型相同的情况下(比如图片)。这是为了节省带宽和提高性能。
2. **服务器端的配置问题**:Nginx 启用了 h2 协议没错,但要确保它的后端服务没有其他限制。比如如果你用的是某些代理或者负载均衡器,它们可能不完全支持 HTTP/2 的多路复用特性。
3. **fetch 的行为**:fetch API 本身是不会阻塞或者排队的,但如果你的网络环境或者服务器响应速度较慢,可能会让你误以为是串行发起的。
你可以试试以下方法来排查和解决:
- **检查 Nginx 配置**:确保你的 Nginx 是最新版本,并且正确启用了 HTTP/2。可以在配置文件中加上
http2参数,比如:- **使用不同类型的资源测试**:尝试把图片换成 JSON 或者其他类型的资源,看看是否还是串行发起。
- **观察时间轴细节**:在开发者工具的网络面板里,仔细看看每个请求的
queueing时间。如果某个请求有明显的排队时间,说明可能是浏览器做了优化。最后,别忘了 HTTP/2 的多路复用虽然很强大,但实际效果还受很多因素影响,比如网络延迟、服务器处理能力等。所以看到串行发起也不一定就是有问题,可能是浏览器或者服务器做了进一步优化。