You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaScript中检测HTTP2/3及解决请求阻塞问题

解决方案:长时ND-JSON请求并发阻塞与HTTP协议版本检测

一、搞定HTTP1.1下长请求占满连接导致的请求挂起问题

1. 给请求排优先级

  • 把长时ND-JSON请求设为低优先级,让关键业务请求先抢占连接。浏览器fetch支持priority参数,直接配置:
    // 长轮询请求设低优先级
    fetch('/long-poll.ndjson', { priority: 'low' });
    // 核心业务接口设高优先级
    fetch('/critical-api', { priority: 'high' });
    
  • 注意:部分老浏览器不支持priority,可以加降级逻辑——维护一个请求队列,检测到当前是HTTP1.1时,将长请求并发数限制在4个以内,预留连接给普通请求。

2. 合并多个长请求到单一连接

  • 不要开8个独立长连接,把所有ND-JSON数据流打包到一个长连接中,每条数据加标识区分来源:
    {"streamId": "order-updates", "data": "..."}
    {"streamId": "user-notifications", "data": "..."}
    
    客户端收到数据后,按streamId分发到对应处理逻辑。仅用1-2个长连接就能替代原来的8+个,直接绕开HTTP1.1的连接限制。

3. 让长请求主动“腾位置”

  • 检测到HTTP1.1时,给长请求加“心跳休眠”机制:运行一段时间后主动断开连接,休眠几秒再重新建立,期间释放连接给其他请求使用。示例代码:
    function startLongPoll(streamId) {
      const controller = new AbortController();
      fetch(`/long-poll.ndjson?stream=${streamId}`, { signal: controller.signal })
        .then(res => {
          // 处理数据流逻辑...
          // 30秒后主动断开,5秒后重连
          setTimeout(() => {
            controller.abort();
            startLongPoll(streamId);
          }, 30000);
        })
        .catch(() => {
          // 异常时自动重连
          setTimeout(() => startLongPoll(streamId), 5000);
        });
    }
    

4. 多域名方案仅在HTTP1.1下启用

  • 不要一直用多别名域名轮询,仅在检测到当前是HTTP1.1时才切换到多域名,HTTP2/3下复用主域名。既解决HTTP1.1的连接限制问题,又不浪费HTTP2/3多路复用的性能优势。

二、准确检测HTTP协议版本的靠谱方法

1. 解析响应头Alt-Svc(首推)

  • 发起一个简单探测请求,解析响应头中的Alt-Svc字段,结合Connection字段辅助判断:
    async function getHttpProtocol() {
      const res = await fetch('/probe-protocol');
      // 优先判断HTTP2/3支持
      const altSvc = res.headers.get('Alt-Svc');
      if (altSvc) {
        if (altSvc.includes('h3=')) return 'HTTP/3';
        if (altSvc.includes('h2=')) return 'HTTP/2';
      }
      // 再判断HTTP1.1
      const connection = res.headers.get('Connection');
      if (connection === 'keep-alive') return 'HTTP/1.1';
      return 'HTTP/1.0';
    }
    
  • 优势:Alt-Svc是服务器告知客户端的可用替代协议,即使存在负载均衡,也能反映实际的协议支持情况,比服务器硬返回标识更可靠。

2. 用并发请求的时间差判断

  • 发起两个空请求,计算完成时间差:
    • HTTP2/3下多路复用,两个请求几乎同时完成,时间差通常小于20ms;
    • HTTP1.1下受连接限制,第二个请求需等待,时间差一般超过50ms。
    async function detectProtocolBySpeed() {
      const start = performance.now();
      await Promise.all([fetch('/empty'), fetch('/empty')]);
      const cost = performance.now() - start;
      // 阈值可根据自身环境调整
      return cost < 20 ? 'HTTP/2+' : 'HTTP/1.1';
    }
    
  • 优化:多次测试取平均值,结合Alt-Svc结果交叉验证,减少误判概率。

3. 用navigator.connection.effectiveType做辅助参考

  • 该属性无法直接检测协议,但effectiveType为4g/5g时,浏览器大概率使用HTTP2/3;3g及以下可能回退到HTTP1.1。仅作为辅助判断,不能单独作为依据。

内容的提问来源于stack exchange,提问作者AI0867

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 13:22:41