64

我们在日志中看到了很多错误 H18(请求中断)。应该如何解释这些,因为 sock=client 在所有情况下我都假设它是断开连接的客户端。因此,忽略这些是否安全?

4

6 回答 6

57

这通常表示用户的网络已断开连接(例如,这种情况在移动用户中经常发生)或最终用户关闭了他们的浏览器或类似的(例如,按下停止,转到不同的页面等)。

您可以安全地忽略那些在本质上使用“sock=client”标记为客户端的那些,但可能想要调查那些被服务器端关闭的那些(“sock=server”)。

于 2013-02-05T15:43:30.710 回答
47

编辑(2015 年 8 月 10 日):我在下面对 H18 错误的回答已过时。Heroku改变了 H18 错误的行为,使它们比以前更具体(和严重)。这个答案现在更正确了。


H18 错误

我最近向 Heroku 支持询问了有关我的应用程序收到大量 H18 错误(有时每小时 3-4 个)并出现在新 Heroku 仪表板的 Metrics 部分的信息(上面的屏幕截图)。我引用了catsby 在此线程上的回复,并要求确认它们是否实际上不可操作。这是我从 Heroku 支持收到的回复:

我刚刚在您的应用程序上浏览了过去 24 小时的 H18。他们都是 sock=client 并且看着 User-Agent 我看到了很多常见的罪魁祸首。大多数情况下,移动浏览器以及我在几天前看到其他应用程序的最新 Chrome 也存在问题。除非您看到诸如特定 URL 或用户之类的模式,否则它通常只是网络问题。

[这些 H18 错误] 不可行并不总是正确的。有些应用程序确实关心它,有时它也可能意味着客户端崩溃而不是网络错误。浏览器确实不时崩溃,但特别是移动浏览器可能非常脆弱。如果应用使用大量资产并触发“页面无响应”错误,您可能会在 H18 中看到峰值。在这种情况下,有时您可以采取一些措施。其他应用程序完全在有线网络中提供服务,并且永远不会想到它,在这种情况下可能存在故障交换机或防火墙。为了透明起见,我们仍然希望报告这些错误,因为无法判断它们是否可操作。

总而言之,如果它们是sock=client错误的,大多数情况下您可以忽略它们,但这确实表明客户端正在断开连接,这可能表明存在真正的问题,具体取决于您的应用程序与其客户端的联网方式(例如移动设备或非常糟糕的网络连接)。 ..但也许你可以放心地忽略它们。

于 2014-11-06T16:01:03.903 回答
34

仅供参考:Ben SheldonCatsby 的答案不再正确。他们在撰写本文时,但情况发生了变化。H18 现在总是 sock=server。Heroku 为 sock=client 添加了一个新的错误代码 H27。

详细信息:https ://devcenter.heroku.com/changelog-items/662

现在应该更加认真地对待 H18,因为它们绝对是您服务的问题。通常可以安全地忽略 H27,因为它们是客户的问题。

于 2015-08-10T15:13:40.293 回答
12

还有另一种情况可能导致Heroku 未记录的此错误。

如果您的服务器响应请求并在未读取请求正文的情况下关闭连接,则路由器将响应 H18 错误。Heroku 路由器日志将显示sock=backend

在这种情况下,您的服务器在 HTTP 规范方面没有做错任何事情。这是 Heroku 路由器的错误。

我就此联系了 Heroku 技术支持,他们确认了这个问题。它将在他们正在实施的路由器的新版本中得到修复。

解决方法是始终确保在关闭连接之前在后端服务器上读取请求正文。

于 2020-07-23T15:37:26.813 回答
0

万一有人遇到这种 H18 错误情况 - 该解决方案适用于我使用 Postgresql 和 SQLAlchemy 的简单 Python 3.9.2 Flask 应用程序。

我必须确保每个路由端点函数都明确读取完整的请求正文。就我而言,这与请求或响应消息中的长请求、超时或大数据无关。

我根据我发现的建议这种解决方案的帖子将此行添加到每个函数的顶部来解决此问题。

@app.route("/store/<int:store_id>")
def get_store_by_id(store_id):
    # ALL requests need to read the full request body on Heroku / Flask
    hack = request.data
...

添加此应用程序后,应用程序完美运行 - 如果我删除 request.data 调用,应用程序将随机失败,出现 H18 错误,没有其他诊断。一旦它开始失败,它将开始对所有请求都失败。

于 2021-05-11T18:39:53.987 回答
0

如果你正在运行一个 golang 应用程序,有一个奇怪的情况是你需要耗尽请求的主体。如果以下情况属实,我能够在 heroku 路由器中重现此错误:

  1. 响应体很大
  2. HTTP 请求的类型为 POST
  3. POST 请求有一个主体(甚至是一个空的)

这是重现和修复它的代码:

...
// To force a Heroku H18 error
// curl -i \
//         -X POST \
//         -H "content-type: application/json" \
//         -H "content-length: 2" \
//         -d "\"{}\"" \
//         "http://localhost:8081/h18"
func h18(w http.ResponseWriter, r *http.Request) {
    // This fixes it
    drainBody(w, r)

    data := dummyBigResponse()
    jData, _ := json.Marshal(data)
    w.WriteHeader(http.StatusOK)
    w.Write(jData)
}

func dummyBigResponse() map[string]string {
    dummyResponse := map[string]string{}
    for i := 1; i < 1000; i++ {
        dummy := fmt.Sprintf("dummy-%d", i)
        dummyResponse[dummy] = "herokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuherokuheroku"
    }
    return dummyResponse
}

// Heroku's suggestion to drain the body
func drainBody(w http.ResponseWriter, r *http.Request) {
    // check if we have a body too big for buffering
    if r.Body != nil || r.Body != http.NoBody || r.ContentLength >1e6 {
        io.Copy(ioutil.Discard, r.Body)
    }
}
...

如果没有drainBody调用,您将收到 H18 路由器错误。有了它,你不会。我希望他们记录下来,因为他们知道这是一个问题!我对此表示支持。

于 2022-01-20T03:31:53.093 回答