Heroku 截断 HTTP 响应?

Posted

技术标签:

【中文标题】Heroku 截断 HTTP 响应?【英文标题】:Heroku truncates HTTP responses? 【发布时间】:2013-03-02 22:24:08 【问题描述】:

我正在 Heroku Cedar 测功机上运行 Flask/Gunicorn Python 应用程序。该应用程序将JSON responses 返回给其客户(实际上是API server)。

客户端偶尔会收到 0 字节的响应。然而,不是我归还它们。这是我的应用程序日志的 sn-p:

3 月 14 日 13:13:31 d.0b1adf0a-0597-4f5c-8901-dfe7cda9bce0 应用程序[web.1] [2013-03-14 13:13:31 UTC] 10.104.41.136 apisrv - api_get_credits_balance(): session_token=[MASKED]

上面的第一行是我开始处理请求。

3 月 14 日 13:13:31 d.0b1adf0a-0597-4f5c-8901-dfe7cda9bce0 应用程序[web.1] [2013-03-14 13:13:31 UTC] 10.104.41.136 apisrv 1252148511 api_get_credits_balance():返回 ['credits_balance': 0]

第二行是我返回一个值(给 Flask——它是一个 Flask“响应”对象)。

3 月 14 日 13:13:31 d.0b1adf0a-0597-4f5c-8901-dfe7cda9bce0 应用程序[web.1] “10.104.41.136 - - [14/Mar/2013:13:13:31] “发布 /get_credits_balance?session_token=屏蔽 HTTP/1.1" 200 22 "-" “Appcelerator Titanium/3.0.0.GA (iPhone/6.1.2; iPhone OS; en_US;)”

第三行是 Gnicorn 的,在这里你可以看到 Gunicorn 获得了 200 状态和 22 字节的 HTTP 正文(“200 22”)。

但是,客户端获得了 0 个字节。这是 Heroku 路由器日志:

3 月 14 日 13:13:30 d.0b1adf0a-0597-4f5c-8901-dfe7cda9bce0 heroku[路由器] at=info 方法=POST 路径=/get_credits_balance?session_token=MASKED 主机=matchspot-apisrv.herokuapp.com fwd="66.87.116.128" dyno=web.1 队列=0 等待=0ms 连接=1ms 服务=19ms 状态=200 字节=0

为什么 Gunicorn 返回 22 个字节,但 Heroku 看到 0,并且确实将 0 个字节传回给客户端?这是 Heroku 的错误吗?

【问题讨论】:

你注意到了吗,heroku 时间戳在你的进程时间戳之前?你用gevent吗?我认为同步有问题。 然而,时间戳表示 1 秒的差异,而不是 1 1 毫秒......我没有使用 heroku,所以这只是建议。 1ms 和 1999ms 都可以给你 1 秒的时间戳差异。服务 19ms 在云服务上也太低了,无法实现。所以我的意思是,可能存在某种超时和超时而不是错误 heroku 服务空页面。这个建议很长,但也许你应该效仿 long request 看看会发生什么 当您与 Heroku 联系时(出于好奇)对他们有多大帮助? 到目前为止还不是很多。我在 10 天前找到了他们,并被告知 Python 人员会先查看它,如果他们无法帮助我,那么路由人员会查看。 5 天后,我被告知 Python 人员已将此传递给路由人员,今天我收到一封来自“路由人员”的电子邮件,说他无法重新创建并要求提供更多信息。所以是的,他们正在通过正确的过程,但这需要永远。 小更新:尚未解决。我一直在与 Heroku 支持来回通信,我现在能收集到的最好的结果是他们并没有以“它在你的尽头”而解雇我,并且正在尝试编写一个工具来 tcpdump-capture 应用程序流量, 用于“调试这样的案例”。 【参考方案1】:

我知道我在这里可能会被认为有点离谱,但还有另一种选择。

我们知道在运输过程中不时会发生错误。我们知道目前我们无能为力来阻止该问题。如果您只提供 API,则停止阅读,但如果您也编写客户端,请继续。

该错误是已知情况和已知原因。空返回值的结果意味着出现问题。但是,该值是可用的,并且已被获取、计算,等等……作为开发人员,我的直觉是将空结果视为 HTTP 错误并请求重新发送数据。然后,您可以跟踪重新发送请求并查看这种情况发生的频率。

我会建议(尽管你觉得我也是那种会想到这一点的开发人员)计算请求并设置一个合理的值来响应用户的“网络错误”。我的直觉是立即重试,然后再等一会儿再重试。

根据您的描述,第一次重试可能会正确获取数据。当然,这可能意味着将较旧的请求保留在缓存中几分钟,或者根据最合适的方式再次运行请求。

这也将绕过任何数量的其他点对点网络错误,并让应用程序更加健壮,即使在面临连接问题时也是如此。

我知道我们作为开发人员的本能是修复已知故障,但有时最好开发一个能够在出现故障时运行的系统。也就是说,记录错误和问题并尝试修复它们永远不会有坏处。

【讨论】:

其实这不是一个不好的评论(虽然可能应该在评论中而不是在答案中),不要以为我没有考虑过......问题是客户无法再次发出请求,因为该请求可能具有服务器端副作用(例如第二次转账)。解决方案是让客户端发出 request_id,并让服务器保留“在过去 60 秒内提供了哪些 request_id”的列表。当客户端收到带有 0 字节正文的 200 响应时,它会重新发出具有相同 ID 的请求,并且服务器不会重新执行(继续) (继续)整个事情。但是,这太丑了,我选择不实施。 我几乎不是缓存的初学者,但在我看来:发送一个随机字符串作为请求的一部分,并缓存结果。当您使用相同的随机字符串重新发送请求时,您自然会获取缓存的结果(相同的内容,相同的来源......),但是当您发送一个合法的新请求时,您有一个新的随机字符串,因此没有缓存结果。

以上是关于Heroku 截断 HTTP 响应?的主要内容,如果未能解决你的问题,请参考以下文章

由于 json 大小,http 请求失败 - 响应 503 和 Heroku 错误 H13

JSONP 响应被截断

为啥 Nginx 会截断 gRPC 流式响应?

flask服务器有时会截断长json响应

Firefox 开发者工具截断长网络响应,Chrome 不显示

Heroku 上的 ActionCable 服务器响应时间