我有一个Django应用程序web应用程序,我想知道nginx是否可以将abort/close传播到uwsgi/Django。
基本上,我知道nginx知道过早中止/关闭,因为它默认为uwsgi_ignore_client_abort
关闭,当请求在响应发送前中止/关闭时,你会在nginx日志中得到nginx 499错误。一旦uwsgi完成处理请求,当它返回到nginx的响应时,它会抛出一个“IO错误”。
将uwsgi\u ignore\u client\u abort
设置为“开”只会使nginx不知道中止/关闭,并删除uwsgi“IO错误”,因为uwsgi仍然可以写回nginx。
我的用例是,我有一个应用程序,其中人们可以快速浏览一些ajax结果,因此,如果快速浏览页面,我将中止他们跳过的页面的挂起ajax请求,这将保持客户机干净高效。但是这对服务器端(uwsgi/Django)没有任何作用,因为即使没有任何东西等待响应,它们仍然必须处理每个请求。
现在很明显,可能有某些页面,我不希望请求因任何原因而过早中止。但是我使用芹菜来处理可能属于这一类的长时间运行的请求。
那么这可能吗?uwsgi的hariakari设置让我认为它在某种程度上......只是不知道如何做到这一点。
我的用例是,我有一个应用程序,其中人们可以快速浏览一些ajax结果,因此,如果快速浏览页面,我将中止他们跳过的页面的挂起ajax请求,这将保持客户机干净高效。
在客户端中止AJAX请求是通过XMLHttpRequest完成的。中止()
。如果调用abort()
时请求尚未发出,则请求不会发出。但是,如果请求已发送,服务器将不知道请求已中止。连接不会被关闭,不会有任何消息发送到服务器,什么也没有。如果希望服务器知道不再需要某个请求,则基本上需要找到一种方法来识别请求,以便在发出初始请求时获得该请求的标识符。然后,通过另一个AJAX请求,您可以告诉服务器应该取消先前的请求。(如果你搜索关于abort()
的问题,比如这个问题,然后搜索“server”,你会找到与此相同的解释。)
请注意,uwsgi\u ignore\u client\u abort
是在TCP级别处理连接关闭的功能。这与中止AJAX请求不同。在JavaScript中,通常没有需要关闭TCP连接的操作。浏览器优化连接的创建和销毁以满足其需要。刚才我是这样做的:
>
我使用lsof
检查是否有任何进程连接到示例。com
。没有。(lsof
是一个*nix实用程序,允许列出打开的文件。网络连接是*nix中的“文件”。)
我打开了一页来举个例子。com在Chrome中lsof
显示了连接和打开连接的进程。
然后我关闭了页面。
我用lsof
进行了轮询,以查看我之前标识的连接是否仍然打开。在我关闭页面后,它保持了大约一分钟的打开状态,即使没有必要保持连接打开。
而且,不需要再修改uswgi设置,就可以知道通过XMLHttpRequest执行的中止。中止()
您给出的用例场景是用户通过一些结果快速分页的场景。对于问题中的描述,我可以看到两种可能性:
>
用户在进一步分页之前等待刷新。例如,爱丽丝正在浏览一个按字母顺序为用户“芝诺”排序的用户名列表,每次显示一个新页面时,她都会看到名称不在那里,页面向下。在这种情况下,没有什么要中止的,因为用户的操作依赖于首先处理的请求。(用户必须在做出决定之前看到新页面。)
用户只需向下翻页,无需等待刷新。爱丽丝又在找“芝诺”,但她想它会出现在最后一页,所以点击,点击,点击她就去了。在这种情况下,您可以取消对服务器的请求。然后按下下一页按钮,增加应该显示给用户的页数,但不要立即发送请求。相反,在用户停止单击按钮后,您会等待一个小的延迟,然后发送带有最终页码的请求,因此您会发出一个请求,而不是一打请求。下面是为DataTables搜索执行的去盎司的示例。
现在很明显,可能有某些页面,我不希望由于任何原因导致请求过早中止。
这正是采取这种或那种方式背后的问题。
>
显然,您可能不想继续花费系统资源来处理已经中止的连接,例如,昂贵的搜索操作。
但是,可能连接非常重要,即使客户端断开连接,也必须对其进行处理。
>
例如,同样昂贵的搜索操作,但实际上不是特定于客户端的,并且将由nginx为所有后续客户端缓存。
或者可能是修改应用程序状态的操作—您显然不希望应用程序的状态不一致!
如前所述,问题在于uWSGI,而不是NGINX。然而,如果你不亲自向uWSGI透露你的意图,你就不能让uWSGI自动决定你的意图。
您将如何在代码中准确地揭示您的意图?许多编程语言并不真正支持多线程和/或异步编程模型,这使得取消操作非常重要。
因此,这里没有神奇的解决方案。甚至像Golang这样的并发友好编程语言也在Cancel的上下文方面存在问题-您可能必须在每个可能阻塞的函数调用中传递它,这使得代码非常难看。
您是否已经在Django中传递了上述上下文?如果没有,那么解决方案很难看,但非常简单-任何时候都可以明确中止请求,检查客户端是否仍然与uwsgi连接。是否已连接(uwsgi.connection\u fd())
: