我目前正在开发一个网站,该网站在 Google Chrome 上触发 net::ERR_HTTP2_PROTOCOL_ERROR 200
错误。我不确定究竟是什么引发了这个错误,我只是注意到它只有在以 HTTPS 访问网站时才会弹出。我不能 100% 确定它是相关的,但看起来它会阻止 JavaScript 正确执行。
例如,发生以下情况:
我正在使用 HTTPS 访问网站
我通过 https://publish.twitter.com 集成的 Twitter 提要根本没有加载
我可以在控制台中注意到 ERR_HTTP2_PROTOCOL_ERROR
如果我删除加载 Twitter 提要的代码,错误仍然存在
如果我以 HTTP 访问该网站,则会出现 Twitter 提要并且错误消失
谷歌浏览器是唯一触发错误的网络浏览器:它在 Edge 和 Firefox 上运行良好。 (注意:我用 Safari 尝试过,我也有类似的 kcferrordomaincfnetwork 303
错误)
我想知道它是否与服务器返回的标头有关,因为错误中提到了“200”,并且 404 / 500 页面没有触发任何内容。
问题是根本没有记录错误。谷歌搜索给我的结果很少。此外,我注意到它出现在最近的 Google Chrome 版本中;该错误不会在 v.64.X 上弹出,但在 v.75+ 上会出现(无论操作系统如何;我正在使用 Mac tho)。
可能与 Firefox 上的网站正常有关,但与 Safari 上无关(kCFErrorDomainCFNetwork 错误 303)和 Chrome(net::ERR_SPDY_PROTOCOL_ERROR)
进一步调查的结果如下:
- 如果服务器返回 404 而不是 2XX,则错误不会在完全相同的页面上弹出
- 使用 HTTPS 证书不会在本地弹出错误
- 在使用不同证书的不同服务器上弹出错误(两者都是 OVH)
- 无论使用什么 PHP 版本,从 5.6 到 7.3,都会弹出错误(使用的框架:Cakephp 2.10)
根据要求,以下是失败资源的返回标头,即整个网页。即使在每个具有 HTTP 标头 200 的页面上触发错误,这些页面总是在客户端的浏览器上加载,但有时会丢失一个元素(在我的示例中,外部 Twitter 提要)。网络选项卡上的所有其他资产都有成功返回,但整个文档本身除外。
Google Chrome 标头(有错误):
Firefox 标头(无错误):
控制台中的 curl --head --http2
请求返回以下成功:
HTTP/2 200
date: Fri, 04 Oct 2019 08:04:51 GMT
content-type: text/html; charset=UTF-8
content-length: 127089
set-cookie: SERVERID31396=2341116; path=/; max-age=900
server: Apache
x-powered-by: PHP/7.2
set-cookie: xxxxx=0919c5563fc87d601ab99e2f85d4217d; expires=Fri, 04-Oct-2019 12:04:51 GMT; Max-Age=14400; path=/; secure; HttpOnly
vary: Accept-Encoding
尝试使用 chrome://net-export/ 和 https://netlog-viewer.appspot.com 工具更深入地告诉我请求以 RST_STREAM 结尾:
t=123354 [st=5170] HTTP2_SESSION_RECV_RST_STREAM
--> error_code = "2 (INTERNAL_ERROR)"
--> stream_id = 1
对于我在 另 一篇文章中读到的内容,“ 在 HTTP/2 中,如果客户端想要中止请求,它会发送一个 RST_STREAM。当服务器接收到一个 RST_STREAM 时,它将停止向客户端发送 DATA 帧,从而停止响应(或下载)。该连接仍可用于其他请求,并且与已中止的请求/响应并发的请求/响应可能会继续进行。[…] 有可能当 RST_STREAM 从客户端到服务端,请求的全部内容在传输中,会到达客户端,客户端会丢弃,但是对于大的响应内容,发送一个RST_STREAM可能有很好的机会在整个请求之前到达服务端响应内容被发送,因此将节省带宽。 ”
所描述的行为与我可以观察到的行为相同。但这意味着浏览器是罪魁祸首,然后我不明白为什么它会发生在两个相同的页面上,一个具有 200 标题,另一个具有 404(如果我禁用 JS,也是如此)。
原文由 Tristan G 发布,翻译遵循 CC BY-SA 4.0 许可协议
我没有弄清楚到底发生了什么,但我找到了解决方案。
OVH 的 CDN 功能 是罪魁祸首。我将它安装在我的主机服务上,但因为我不需要它而对我的域禁用。
不知何故,当我启用它时,一切正常。
我认为它迫使 Apache 使用 HTTP2 协议,但我不明白的是,我的每个标题中确实提到了 HTTP2,我认为这意味着服务器正在使用正确的协议进行响应。
因此,针对我的特殊情况的解决方案是在所有相关域上启用 CDN 选项。
如果有人更好地理解这里可能发生的事情,请随时分享解释。