【问题标题】:Django AJAX requests during regular request not going through常规请求期间的 Django AJAX 请求未通过
【发布时间】:2017-01-03 02:09:28
【问题描述】:

我有一个带有登录网页的 Django 站点。当页面上的登录表单被提交时,它会执行登录视图,该视图在其中运行一个需要很长时间(30 秒左右)处理的函数。因此,为了在登录过程中向客户端显示进度,一旦提交表单,登录页面上的一个 JS 函数就会开始向服务器发出 AJAX POST 请求(到 poll_state 视图),它返回的状态登录。然后它会更新登录页面的 html 以显示状态(如加载栏)。

我的问题或问题是,当我使用 NGINX 代理服务器执行常规 python manage.py runserver 时,它可以完美运行。但是当我使用 Gunicorn 而不是 python manage.py runserver 时,AJAX 请求在登录视图完全处理并返回响应(即下一个网页)之前不会通过。它不是轮询登录状态,而是在下一个网页加载后返回poll_state 视图的一堆错误。

当用户提交登录表单时,服务器执行登录视图,同时客户端开始使用 AJAX 请求轮询服务器。这是登录网页上发送请求的JS代码:

      let willstop = 0
      var poll = function() {
        $.ajax({
          url:'http://<my server's ip>/poll_state/',
          type: 'POST',
          data: {
              csrfmiddlewaretoken: $("input[name='csrfmiddlewaretoken']").val(),
              id: $('#id').val(),
          },
          success: function(pollResult) {
            step = pollResult.data
            if (step == 'Done')
              willstop = 1
            $('#step').html(step)
          }
        })
      }
      let refreshIntervalId = setInterval(function() {
        poll()
        if(willstop == 1) {
          clearInterval(refreshIntervalId);
        }
      }, 500)

它只是每半秒向我的服务器的poll_state 视图发送一个请求(我省略了我的服务器地址,但如果有帮助可以分享它!)直到登录完成(步骤==“完成”),并且然后它只是清除间隔(这有点多余,因为它无论如何都会重定向到新页面)。

还有poll_state 视图:

def poll_state(request):
    """ A view to report the progress to the user """

    data = 'Fail'
    if request.is_ajax() and request.method == 'POST':
        data = loggingInSteps[request.POST.get('id')]
    else:
        data = 'This is not an ajax request'

    result = {'data': data}
    return JsonResponse(result)

loggingInSteps 是服务器上的全局字典,其中包含所有客户端的步骤。每个客户端都有一个唯一的 id,它是键,值是客户端在登录过程中所处的步骤。键值对在重定向时被删除。

我运行它的服务器是 64 位 Ubuntu DigitalOcean droplet,所以它应该是我的生产服务器。我按照this tutorial设置服务器,所以我的NGINX配置是:

server {
  listen 80;
  server_name cume;

  location / {
    proxy_pass http://127.0.0.1:8000;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  location /static/ {
    alias /home/mikmaks/dev/CUNYsecond/cume/static/;
  }
}

我启动 Gunicorn 或者像这样 gunicorn config.wsgi --bind 127.0.0.1:8000 或者像这样的守护进程:gunicorn config.wsgi --bind 127.0.0.1:8000 --daemon --log-file ~/dev/logs/cume_gunicorn.log --workers=3 任何一个版本都不起作用。

有人知道 Gunicorn 是否可以从同一个客户端接收 AJAX 请求,因为它正在处理来自它的正常请求?也许问题不是 Gunicorn,而是我的 NGINX 配置。非常感谢你的帮助。如有必要,我很乐意提供任何代码或其他信息:)

【问题讨论】:

  • 您所指的错误是什么 - 它们在浏览器控制台中吗?
  • 是的,浏览器控制台抛出 500 内部服务器错误并且终端窗口给出了我试图访问不存在的东西(字典中的键值对)的错误,但它确实存在,只是它试图在poll_state 视图中访问的键值对在登录完成后被删除。只有在加载下一页后才会出现错误! (抱歉,我认为这很重要)
  • 需要在问题中添加 3 件事 1. 你的 nginx 配置 2. 你在哪里运行 python manage.py runserver,本地服务器还是生产服务器? 3.你的gunicorn worker配置是什么
  • 进行了修改,希望对您有所帮助:)
  • 能否贴出失败的python代码sn-p?我敢打赌它与服务器上的多个进程有关(当您使用 runserver 时,它只是一个进程)

标签: ajax django nginx gunicorn


【解决方案1】:

使用异步工作器(在我的例子中,我使用了gevent)工作!现在 Gunicorn 一次处理多个请求,即阻塞一切(登录视图)的请求正在异步处理,因此 AJAX 请求通过。

我现在开始使用 Gunicorn:gunicorn config.wsgi --bind 127.0.0.1:8000 -k gevent --worker-connections 1001 --workers=3。唯一的问题是,当负载在 3 个工作人员之间分配时,它的更新效果并不好,但是有 1 个工作人员它可以完美运行。我得再想办法,看看我能不能让它和 3 名工人一起工作。

感谢 Alex 的帮助!

【讨论】:

  • 很高兴听到我能帮上忙!不过听起来好像是你自己想出来的!
【解决方案2】:

loggingInSteps is a global dict on the server with the steps for all the clients 如果您有多个处理请求的进程,则可能会出现问题。字典可以在一个进程中更新,但不能在另一个进程中更新。也许切换到单进程模式 (--workers=1 ?) 会解决您的问题。

或者,您可以重新设计您的应用程序并摆脱全局 dict 以使其在多进程环境中工作

【讨论】:

  • 我尝试注释掉全局 dict 部分并在 poll_state 函数中返回一个字符串。我也设置了workers=1,但什么都没做。这似乎是别的东西。在登录视图和poll_state 视图结束时,我打印出 JSON,然后它也作为视图的响应发送。在终端窗口中,它首先从登录视图中打印出 JSON,然后从 poll_state 视图中打印出 20 次(或者发送 AJAX 请求的次数)中的字符串。这就像它将 AJAX 请求排队,直到登录请求完成。
  • 我一直在查找与 Gunicorn 相关的内容,也许是因为我使用的是同步工作线程?我应该使用异步的 geventeventlet 工人吗?
猜你喜欢
  • 2018-09-26
  • 1970-01-01
  • 2012-09-04
  • 1970-01-01
  • 2014-08-26
  • 1970-01-01
  • 2013-04-10
  • 1970-01-01
  • 2013-02-15
相关资源
最近更新 更多