【问题标题】:How should I interpret Heroku H18 errors?我应该如何解释 Heroku H18 错误?
【发布时间】:2012-10-03 08:41:08
【问题描述】:

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

【问题讨论】:

  • 我还看到自 2012 年 10 月 1 日以来 Heroku 上的 H18 错误数量有所增加(根据 Loggly 的“图表“错误 H18””)。在此之前它们几乎不存在。 See graph
  • 仅供参考,供其他人发现这一点:自 2015 年 6 月 3 日起,一些以前是 H18 的错误现在是“H27 – 客户端请求中断”。 Read more here. 下面的一些答案中也提到了这一点,但在问题旁边查看可能会有所帮助。
  • @Kristoffer 如果您仍然处于活动状态,那么接受其中一个较新的答案可能是有意义的,因为自从您最初提出要求以来,这已经发生了变化。

标签: heroku


【解决方案1】:

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

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

【讨论】:

  • 如果您收到大量 client 错误怎么办,例如在 Meteor 应用程序上? (我看到的人数远远超过自然关闭标签或丢失单元格信号的人数。)您知道还有其他可能导致此错误的事情吗?
  • 这不再是真的!不要忽视这些。有关详细信息,请参阅下面的答案。
【解决方案2】:

编辑(2015 年 8 月 10 日):我在下面对 H18 错误的回答已过时。 Heroku 有changed the behavior of H18 errors 使它们比以前更具体(和严肃)。这个Answer 现在更正确了。


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

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

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

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

【讨论】:

  • 我在新的 Heroku 仪表板上也看到了很多这些红色的 H18 错误。感谢您复制 Heroku 的回复,这样我就不必自己给他们发消息了 :)
  • 一小时 3-4 次?我每秒得到大约 50 个!
【解决方案3】:

仅供参考:Ben Sheldon'scatsby's 的答案不再正确。 在撰写本文时,它们是正确的,但情况已经改变。 H18 现在总是 sock=server。 Heroku 为 sock=client 添加了一个新的错误代码 H27。

详情请看:https://devcenter.heroku.com/changelog-items/662

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

【讨论】:

  • 感谢您的更新。我将编辑我的答案以链接到您的答案。
【解决方案4】:

还有另一种情况可能导致此错误不是documented by Heroku

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

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

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

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

【讨论】:

  • 非常感谢您!救了我的命——或者至少是我的晚上!
  • 很抱歉这么晚才问你。这个错误已经解决了吗?客户应该解决这个错误吗?
  • @leedjango,恐怕我不知道。我在 2020 年 7 月从 Heroku 技术支持人员那里听到的最后一个消息是,这是一个“漫长的过程”,他们不知道什么时候会完成。
  • 我想确认我们也看到了这个。如果请求尝试 POST 数据,只需将请求正文读入字符串(尽管没有必要)即可修复它。
  • 只有 7 小时的尝试和挖掘才能找到这个!我不敢相信他们没有记录这一点。谢谢你
【解决方案5】:

万一有人遇到这种 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 错误,没有其他诊断。一旦开始失败,它将开始对所有请求都失败。

【讨论】:

    【解决方案6】:

    如果您正在运行一个 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 路由器错误。有了它,你不会。我希望他们记录下来,因为他们知道这是一个问题!我对此表示支持。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-25
      • 2020-12-27
      • 1970-01-01
      • 2016-03-11
      • 2020-11-04
      • 1970-01-01
      • 2018-11-10
      • 2016-11-23
      相关资源
      最近更新 更多