Django有没有一种打开HTTP长轮询连接的方法?

19

保持连接打开,直到发生事件。


投票?不知道什么是长杆连接,但听起来很棒。 ;) - Dominic Rodger
那会是什么事件呢?Django是一个与请求和响应一起工作的Web框架,而不是一个信令协议。如果我误解了你的问题,很抱歉。 - AndiDog
长轮询是一种用于 AJAX 应用程序的方法,当服务器上发生事件时应立即执行某些操作。基本上,您启动一个 AJAX 请求,但该请求不会立即处理,而是在特定事件发生时处理。收到响应后,请求通常会立即重新启动。 - ThiefMaster
@ThiefMaster。是的,那正是我想做的。我该怎么做呢? - TIMEX
4个回答

16
请参考 Django / Comet (Push): Least of all evils?The latest recommendation for Comet in Python? - COMET 是 "ajax long-polling" 的另一个称呼。
显然,最常见的方法不是直接在django中完成,而是借助于额外的守护进程(可能是因为例如Apache无法很好地处理大量的长时间连接)。现在,nodejs+socketio相当流行(它甚至可以使用WebSockets) - 您只需要找到两个东西之间传递数据的良好方式即可。如果是单向的(例如仅广播到所有连接的客户端),则redis pubsub队列对此来说也不错。
但是http://code.google.com/p/django-orbited/可能是最适合django的解决方案。

Orbited很好,但下一个最好的选择是服务器发送事件;这篇html5rocks.com上的文章解释了更多,并提供了一些你可以使用的代码。 - Burhan Khalid
1
Python中使用socket.io的实现方式:https://gevent-socketio.readthedocs.org/en/latest/ - turtlemonvh

9

给未来的读者 :)

我创建了一个使用Gevent的简单长轮询django类视图,在Github上可以找到它:https://github.com/tbarbugli/django_longpolling,或从pypi(django_longpolling)获取。

编辑:我进行了一些有关Django长轮询/异步工作程序的进一步实验/部署,并且可以说,如果可能的话,选择外部守护程序是一个非常好的选择,特别是当你使用数据库时 (当使用异步工作程序时,你需要一个数据库连接池,否则将会有许多工作程序连接限制到你的数据库连接上限,这并不是期望的情况)。


1
我认为与Django进行异步通信的最佳方式是在另一个端口上有一个节点服务器监听,并使用Socket.io的api客户端。这样,您不会依赖于Django模块的支持,而且非常简单:Node监听来自客户端的请求,将此请求转换为POST请求并发送到侦听Django的端口。 我认为这是最好的方式。

server.js

var http=require('http');
var server = http.createServer().listen(3000);
var io=require('socket.io').listen(server);
var querystring=require('querystring');

io.on('connection',function(socket){
   console.log('Connected to the client');
   socket.on('new comment',function(data){
      console.log('Web--->Node');
      var values=querystring.stringify(data);
      console.log(values);
      var options={
        hostname:'localhost',
        port:'8000',
        path:'/create-comment',
        method:'POST',
        headers:{
          'Content-Type':'application/x-www-form-urlencoded',
          'Content-Length':values.length
        }
      }
      var request=http.request(options, function(response){
        response.setEncoding('utf8');
        response.on('data',function(data){
          //Here return django
          console.log('Django-->Node');
          io.emit('return comment',data);
        });
      });

      request.write(values);
      request.end();
   });
});

views.py

def trysock(request):
    print 'In tryshok'
    comments=Comment.objects.all()
    dic = {
              'name': 'User',
              'form': CommentForm(),
              'comments': comments
          }

    return render(request,'index.html',dic)

@csrf_exempt
def create_comment(request):
    print 'Django<---Node'
    Comment.objects.create(
            user = request.POST['user'],
            comment = request.POST['comment']
        )

    response = JsonResponse({'user' : request.POST['user'], 'comment' : request.POST['comment']})
    print response.content
    return HttpResponse(response.content)

index.html

<div class='col-md-12'>
       <div class='col-md-6'>
         <form method='POST'>
         {% csrf_token %}
         {{form.comment}}
         <button id='boton'>Comentar</button>
         </form> 
       </div>

       <div id='comentarios' class='col-md-6'>
         {% for comment in comments %}
         <p>{{ comment.user }} - {{ comment.comment}}</p>
         {% endfor %}
       </div>
     </div>
    <!-- Fin Formulario comentarios -->

   </div>
    <script>
          var socket=io.connect('http://localhost:3000');
          console.log(socket);
          $('#boton').on('click',Comentar);
          function Comentar(e){
            console.log('Comentar(e)')
            e.preventDefault();
            var datos = {
              user:"baurin",
              comment : 'comentario de prueba'
            };
            socket.emit('nuevo comentario',datos);
            console.log('Enviando....: '+datos.user + '-' + datos.comment);
          }
          socket.on('devolviendo comentario', function(data){
              console.log('Recibiendo...');
              var dato = JSON.parse(data);
              $('#comentarios').prepend('<p>' + dato.user + '-' + dato.comment + '</p>')
          });
        </script> 

0

2022年,官方的Django Channels让你可以处理长轮询工作负载。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接