Heroku截断HTTP响应?
我在 Heroku 的 Cedar dyno 上运行一个 Flask/Gunicorn 的 Python 应用。这个应用会给客户端返回 JSON 响应
(其实就是一个 API 服务器
)。
偶尔会有客户端收到 0 字节的响应。但这不是我故意返回的。下面是我应用日志的一部分:
3月14日 13:13:31 d.0b1adf0a-0597-4f5c-8901-dfe7cda9bce0 app[web.1] [2013-03-14 13:13:31 UTC] 10.104.41.136 apisrv - api_get_credits_balance(): session_token=[已隐藏]
上面的第一行是我开始处理请求的记录。
3月14日 13:13:31 d.0b1adf0a-0597-4f5c-8901-dfe7cda9bce0 app[web.1] [2013-03-14 13:13:31 UTC] 10.104.41.136 apisrv 1252148511 api_get_credits_balance(): returning [{'credits_balance': 0}]
第二行是我返回一个值的记录(这是给 Flask 的,实际上是一个 Flask 的“响应”对象)。
3月14日 13:13:31 d.0b1adf0a-0597-4f5c-8901-dfe7cda9bce0 app[web.1] "10.104.41.136 - - [14/Mar/2013:13:13:31] "POST /get_credits_balance?session_token=已隐藏 HTTP/1.1" 200 22 "-" "Appcelerator Titanium/3.0.0.GA (iPhone/6.1.2; iPhone OS; en_US;)"
第三行是 Gunicorn 的记录,你可以看到 Gunicorn 收到了 200 状态码和 22 字节的 HTTP 内容("200 22
")。
但是,客户端却收到了 0 字节的响应。下面是 Heroku 路由器的日志:
3月14日 13:13:30 d.0b1adf0a-0597-4f5c-8901-dfe7cda9bce0 heroku[router] at=info method=POST path=/get_credits_balance?session_token=已隐藏 host=matchspot-apisrv.herokuapp.com fwd="66.87.116.128" dyno=web.1 queue=0 wait=0ms connect=1ms service=19ms status=200 bytes=0
为什么 Gunicorn 返回了 22 字节,但 Heroku 却看到 0 字节,并且确实返回了 0 字节给客户端呢?这是 Heroku 的 bug 吗?
1 个回答
我知道我可能有点不按常理出牌,但其实还有另一种选择。
我们都知道,有时候在数据传输过程中会出现错误。现在我们能做的事情不多,无法完全避免这个问题。如果你只是提供API,那就可以停止阅读了;但如果你也在写客户端代码,那就继续看下去。
这个错误是一个已知的问题,原因也很明确。返回一个空值意味着出了点问题。不过,数据其实是可以获取到的,可能是计算出来的,或者其他什么原因……作为开发者,我的直觉是把这个空结果当作HTTP错误来处理,然后请求重新发送数据。这样你就可以追踪这些重新发送的请求,看看这种情况发生的频率。
我建议(虽然我觉得你也会想到这一点)统计一下请求的次数,并为用户设置一个合理的“网络错误”响应值。我的直觉是立即重试,然后再等一会儿再重试几次。
根据你的描述,第一次重试应该能正确获取到数据。当然,这可能意味着要在缓存中保留旧请求几分钟,或者根据情况决定是否重新发送请求。
这样做还可以绕过其他各种点对点的网络错误,让应用在面对连接问题时更加稳定。
我知道作为开发者,我们的本能是去修复已知的错误,但有时候,建立一个能够在出现故障时仍然正常工作的系统更为重要。话虽如此,记录错误和问题并尝试修复它们也是有必要的。