以下是我对一个有趣的错误的讨伐,虽然我已经解决了,但我不明白。我找到了一个解决方案,但我真的希望有人可以提供一些有关错误的实际原因的见解。
此问题首先出现在我们的Django应用程序的生产服务器上。堆栈如下
我们的团队在Safari上发现了一个POST请求的问题。 Safari会响应响应并吐出ERR_INCOMPLETE_CHUNKED_ENCODING
。邮寄请求如下:
class ContractCloseOutSubmitView(APIView):
def post(self, request, contract_id):
contract = get_object_or_404(
ContractCloseOut, pk=contract_id)
if contract.submit():
return Response({"detail": "Closed successfully."}, status=200)
else:
raise ParseError("Could not submit.")
请求是将对象标记为已关闭的简单请求。我们在网站的许多地方使用这种模式,所以这个问题显然需要引起注意。
我们的第一个线索是请求 关闭了对象。也就是说,必须已到达行if contract.submit()
。这会将问题缩小到响应范围。我做了一些阅读,这个错误有很多原因。我们试过了:
没有任何效果,问题仍未在当地发生。所以我们决定在本地复制整个堆栈并进行测试。一次一个,我们删除了网络层的元素,并确定删除nginx并直接与uWSGI交谈解决了这个问题。
所以现在我们确信问题在于nginx,但仍然没有解决方案。好吧,在Google的第三页深处,我遇到了一篇StackOverflow帖子,其中有一个简短的评论,提到阅读请求正文对nginx的缓冲区有什么影响以及如何它判断内容长度(这是我不太熟悉的东西)。无论如何,显然解决问题的方法是简单地读取缓冲区。也就是说,使用请求正文。所以我尝试通过将其值赋给变量来触摸请求体:
class ContractCloseOutSubmitView(APIView):
def post(self, request, contract_id):
data = request.data #touchie touchie
contract = get_object_or_404(
ContractCloseOut, pk=contract_id)
if contract.submit():
return Response({"detail": "Closed successfuly."}, status=200)
else:
raise ParseError("Could not submit.")
ERR_INCOMPLETE_CHUNKED_ENCODING
毕竟,我只是想知道为什么会发生这种情况。什么是不读取可能导致此错误的请求正文?为什么只有nginx?为什么只有Safari?
我希望StackOverflow社区可以帮我解释一下这个!解决它很有趣。我还做了一个简短的presentation与一些同事分享。
答案 0 :(得分:0)
您没有指定nginx的版本。如果它几个月没有更新,可能是这个封闭的问题:
https://trac.nginx.org/nginx/ticket/959
以前,流的窗口保持为零以防止a 客户在请求之前发送请求正文(请参阅 887cca40ba6a了解详情)。直到这样的初始窗口被确认 所有带数据的请求都被拒绝(详见0aa07850922f)。 这种方法揭示了一些问题:一些客户(特别是MS IE / Edge,Safari,iOS应用程序)显示错误甚至崩溃 流被拒绝;这要求每个请求至少有一个RTT 在客户端收到窗口更新并能够发送之前使用body 数据。为了克服这些问题的新指令 " http2_body_preread_size"介绍。它设置了初始窗口 并配置一个特殊的每个流预读缓冲区,用于 在请求和处理正文之前保存所有传入的数据。
我的猜测是创建引用,在设置ack来回传递后保持缓冲区打开。
尝试升级nginx,因为此补丁已合并。如果你升级并仍然有问题,这是一个回归,我打开一个新的nginx票。