从浏览器杀死 Django 进程

Kill Django process from browser

在 Django 视图中,我调用了一个用于上传和导入 excel 文件的函数。

def import_log(request):
    report = ""

    if request.method == "POST":
        file_object = request.FILES
        sheet_name = request.POST["sheet_name"]

        if len(file_object):
            file_object = file_object["file_object"]

        if len(file_object):
            process_import()

            context = {
                "report": report
            }

            return render(request, "import_log.html", context)

        else:
            return import_upload_view(request, error="No file uploaded")

当我尝试通过单击 "Stop loading this page" 或关闭浏览器来停止页面时,导入过程不会停止。

这些导入文件非常大,所以我希望能够在需要时从浏览器中终止进程。

我怎样才能做到这一点?

简而言之,你不能。

互联网的工作原理是向服务器发送请求,然后等待响应,它与进程的开放连接无关,那是服务器处理自己进程的工作。

浏览器本质上只不过是您的计算机显示器,显示发送给它的信息 - 因此您可以随心所欲地关闭显示器或拔下插头,它不会阻止您的计算机运行运行

唯一一次 Django/server 会知道 'aborted connection' 是在它尝试发回响应时。要理解这一点,您可以编写一个虚拟视图并在该视图中睡眠 10 秒;从浏览器调用它并尽可能快地停止它;等着看 Django 做了什么。如果你是 运行 Django Dev 服务器,你应该清楚 Django 确实表现正常并发送响应,但是由于连接中止而发生 500 错误,然后尝试将这个 500 错误发送给客户端,当然显然也失败了。

因此,无法在中间停止查看过程。

但是,您可以通过首先将请求发送到您的视图然后分拆一个新进程来执行 "pretty big" 导入进程来更改解决此问题的方式;通过在某些持久数据存储(可能在数据库中)中使用一些唯一 ID 和当前时间戳来注册进程; return HTTP 状态代码 202(已接受)与注册 ID 结束视图。

在spun进程中,多线程。一个线程不断轮询数据库以检查当前时间与数据库中的时间之间的增量。如果差异超过您决定的阈值(比如 10 秒),则整个过程应该自行结束。

从浏览器继续点击 API(另一个 Django 视图)使用 AJAX 更新数据库中特定记录的时间戳,其 ID 是您在 202 响应中获得的 ID。

这个想法是让服务器知道客户端仍然可用,如果由于某种原因您没有看到来自客户端的任何 ping,您会将其视为浏览器关闭或导航离开页面的情况,所以停止处理分拆出来的流程。

如果您是单页应用程序,这种方法可能会变得棘手。