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

Express.js+SPDY实现HTTP/2仅Chrome报net::ERR_HTTP2_PROTOCOL_ERROR问题

问题解答:Chrome下HTTP/2流式传输出现ERR_HTTP2_PROTOCOL_ERROR

1. 为何仅Chrome出现该错误?

Chrome对HTTP/2协议的合规性校验比Firefox、Edge更严格,主要触发场景包括:

  • HTTP/2不支持Connection: keep-alive这类HTTP/1.1专属头,Chrome会直接判定协议错误,而其他浏览器可能兼容忽略这类非合规头。
  • 流式传输中res.write的调用时机或数据格式违反HTTP/2流帧规则,比如流标记关闭后仍写入数据,或数据帧大小超出Chrome限制。
  • SPDY库的HTTP/2实现存在兼容性问题,Chrome对HTTP/2最新规范支持更激进,而SPDY作为HTTP/2前身,部分细节不符合标准。

2. 该错误的修复方案是什么?

步骤1:移除HTTP/1.1专属响应头

HTTP/2不需要Connection: keep-alive,直接删除该头:

// 删除此行
// res.setHeader('Connection', 'keep-alive');

同时避免使用任何HTTP/1.1逐跳头(如Proxy-Connection、Keep-Alive)。

步骤2:修复流式传输的异步安全

确保res.write调用异步安全,避免流状态异常:

onResponse: async (chunk) => {
  const { dataString } = await extractStrategyData({
    response: chunk,
    isDescription: requestPayload.description,
  });
  // 用Promise包裹res.write,确保写入完成再处理下一个chunk
  await new Promise(resolve => res.write(dataString, resolve));
},

步骤3:调整SPDY配置或替换库

SPDY已多年未维护,建议优先替换为原生HTTP/2模块。若暂时无法替换,升级SPDY并精简配置:

const spdyOptions = {
  spdy: {
    protocols: ['h2', 'http/1.1'], // 移除过时的SPDY协议版本
    plain: false,
    'http2-settings': {
      'MAX_CONCURRENT_STREAMS': 100 // 显式匹配Chrome默认并发流数
    }
  }
}

3. Express.js中处理高并发流式传输的更佳方案是什么?

方案1:直接Pipe上游流到响应流

避免手动处理chunk,利用Node.js流的原生能力,自动适配HTTP/2规则:

app.get('/stream', async (req, res) => {
  const response = await fetch(<API_URL>, httpOptions);
  if (!response.ok) {
    res.status(500).send('Streaming error');
    return;
  }
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  // 直接将上游流pipe到Express响应流
  response.body.pipeThrough(new TextDecoderStream()).pipe(res);
});

方案2:使用SSE专用库

对于Server-Sent Events场景,用成熟库简化流管理:

  • express-sse:为Express设计的SSE库,自动兼容HTTP/1.1和HTTP/2。
  • @microsoft/fetch-event-source:客户端、服务端双向兼容的流式传输库。

方案3:原生HTTP/2 + Express

用Node.js内置http2模块替代SPDY,避免第三方库兼容性问题(见问题4)。

4. Express.js实现HTTP/2有哪些SPDY的替代方案?

方案1:Node.js原生http2模块

最推荐的方案,Node.js v8.4.0起原生支持HTTP/2,兼容性最佳:

const http2 = require('http2');
const fs = require('fs');
const express = require('express');

const app = express();

// 创建HTTP/2安全服务器
const server = http2.createSecureServer({
  key: fs.readFileSync('../localhost.key'),
  cert: fs.readFileSync('../localhost.crt'),
  maxHeaderSize: 64000
}, app);

server.listen(443);

Express路由、中间件可直接复用,无需修改。

方案2:Fastify框架(替代Express)

Fastify对HTTP/2支持更完善,性能更高,原生适配流式传输:

const fastify = require('fastify')({
  http2: true,
  https: {
    key: fs.readFileSync('../localhost.key'),
    cert: fs.readFileSync('../localhost.crt')
  }
});

fastify.get('/stream', async (request, reply) => {
  reply.header('Content-Type', 'text/event-stream');
  reply.header('Cache-Control', 'no-cache');
  const response = await fetch(<API_URL>, httpOptions);
  response.body.pipeThrough(new TextDecoderStream()).pipe(reply.raw);
});

fastify.listen({ port: 443 });

方案3:HTTP/2反向代理中间件

若需反向代理上游服务,可使用http2-proxy中间件配合Express实现HTTP/2代理。


内容的提问来源于stack exchange,提问作者Muhammad Ahmed Habib

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 23:45:03