页面加载不一致 ERR_HTTP2_SERVER_REFUSED_STREAM 错误

Inconsistent ERR_HTTP2_SERVER_REFUSED_STREAM error on page-load

我确实有至少两个 wordpress 站点,它们非常不一致地抛出数量不等的 net::ERR_HTTP2_SERVER_REFUSED_STREAM 错误。当这些错误发生时,抛出的错误数量在页面加载和页面加载(或重新加载)之间变化很大,从 4 个带有该错误的请求到大约 60 个,有时甚至更多(如果页面有很多请求)。实际受影响的 ressources/requests 似乎完全是随机的,因此不要留下任何线索这是从哪里来的。

如果出现这些错误,它们的出现大多会持续存在(当进行简单的页面刷新或硬刷新时),直到浏览器重新启动。很少他们甚至在重启后也会留下来。

当这个 打嗝 确实发生并且 browser/system 进入这种故障状态时,这些错误也会发生在 wordpress 后端加载基本文件时,例如 .../wp-includes/js/wp-lists.min.js?ver=5.7和类似的。

至少有两个用户在 Chrome、Opera 和 Edge 中登录和退出 wordpress 时遇到过这种行为。在 Opera 和 Edge 中,我们没有安装任何浏览器扩展。据我们所知,其他用户从未遇到过此问题,尽管他们中的一些人多次访问该网站。

这可能是什么原因and/or可能有什么解决方法?


两个站点上安装的插件列表:


这与 WordPress 无关。它与使用 HTTP/2 standard.

的 Apache 或 Nginx 有关

REFUSED_STREAM (0x7): The endpoint refused the stream prior to performing any application processing (see Section 8.1.4 for details).

它可能来自过多的并发流:

Endpoints MUST NOT exceed the limit set by their peer. An endpoint that receives a HEADERS frame that causes its advertised concurrent stream limit to be exceeded MUST treat this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR or REFUSED_STREAM. The choice of error code determines whether the endpoint wishes to enable automatic retry (see Section 8.1.4) for details).

它也可以在推送响应操作期间发送:

If the client determines, for any reason, that it does not wish to receive the pushed response from the server or if the server takes too long to begin sending the promised response, the client can send a RST_STREAM frame, using either the CANCEL or REFUSED_STREAM code and referencing the pushed stream's identifier.

或者如果客户端尝试使用 HTTP/1.1 进行连接:

Servers that don’t wish to process the HTTP/1.1 response should reject stream 1 with a REFUSED_STREAM error code immediately after sending the connection preface to encourage the client to retry the request over the upgraded HTTP/2 connection.

我无法确定在这些请求期间发生了什么,因为它可能有多种原因,如上所述。

所以我建议你有几个选择:

  • 通过 Cloudflare 传递您网站的流量,因此它们充当这些连接的中间人并规范化发送到您服务器的请求
  • 您可以增加 SETTINGS_MAX_CONCURRENT_STREAMS 以将发送 REFUSED_STREAM 的风险降至最低。如果你使用 Nginx,你可以在这里看到如何做到这一点:http://nginx.org/en/docs/http/ngx_http_v2_module.html#http2_max_concurrent_streams
  • 如果您不知道如何执行上述操作,请联系您的托管公司并请他们为您执行并升级您的 Nginx 版本,因为已知一些旧版本存在问题。
  • 在 Nginx 中禁用 HTTP/2。
  • 作为最后的资源,您可以迁移到另一家托管公司。

如果您使用 Apache,我上面所说的一切也适用。

I do have at least two wordpress sites which very inconsistently throw a varying number of net::ERR_HTTP2_SERVER_REFUSED_STREAM errors. When these errors occur the number of errors thrown highly differs from say 4 requests to about 60 and sometimes even more (if the page has enough requests),

正如你所说,流错误的数量比请求的数量多。一个可能的解释是流是推送流,它具有偶数流 ID。推流由服务端发起。相反,客户端发起的流具有奇怪的ID。

为什么错误如此重要?

我们按照关键错误词来尝试找到一些路线图。 search key word ERR_HTTP2_SERVER_REFUSED_STREAM in chromium github repo

我们得到以下情况来回复ERROR_CODE_REFUSED_STREAM。

  • 浏览器处理服务器端流RST帧(SpdySession::OnGoAway)。RST帧表示关闭流但不关闭session。 我们可能会收到错误 ERR_HTTP2_SERVER_REFUSED_STREAM

  • 浏览器处理服务器端流 Goway 帧 (SpdySession::OnGoAway)。 Goway框架表示关闭session。服务器端请求 goway 帧没有任何错误(spdy::ERROR_CODE_NO_ERROR)。 我们可能会收到错误 ERR_HTTP2_SERVER_REFUSED_STREAM

错误数远远多于请求数。所以我们可能会被引导到stage conculation。
服务器端高概率发送RST帧

现在我们继续挖掘。

search key word ERROR_CODE_REFUSED_STREAM in chromium github repo

服务器可能会发送 ERROR_CODE_REFUSED_STREAM 以下情况:

  • 当session 属性 enable_push_关闭时,尝试创建推流。
  • session 状态变为 STATE_GOING_AWAY,但收到推送流
  • 没有“:url”的错误推流header
  • 只有 HTTP 方案允许受信任的代理进行跨源推送。如果不是,请拒绝。
  • 推送URL必须有https方案
  • 证书与推送的 URL.
  • 不匹配
  • 具有相同 url 的重复推送流。
  • ERR_TIMED_OUT 或 ERR_HTTP2_CLIENT_REFUSED_STREAM

有用的工具

使用调试工具获取更多信息。

chrome://net-internals/http2#events

chrome://net-export/

关于服务器推送消息

Chrome to remove server push