Django有没有办法打开HTTP长轮询连接?

19 投票
4 回答
18291 浏览
提问于 2025-04-16 10:32

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

4 个回答

1

我觉得用Django进行异步通信的最好方法是搭建一个Node服务器,监听另一个端口,然后使用Socket.io的API客户端。这样的话,你就不需要依赖Django的模块支持,操作起来也很简单:Node服务器接收来自客户端的请求,把这个请求转换成一个POST请求,然后发送到Django,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> 
9

给未来的读者们 :)

我用Gevent创建了一个简单的长轮询Django类视图,你可以在GitHub上找到它,链接是 https://github.com/tbarbugli/django_longpolling,或者在pypi上下载(django_longpolling)。

补充说明:我对Django长轮询和异步工作者做了一些进一步的实验和部署,我可以说,如果有可能,选择一个外部守护进程是一个非常好的选择,特别是当你使用数据库的时候(使用异步工作者时,你需要一个数据库连接池,否则你的工作者连接数量会受到数据库连接限制的影响,这样是不太理想的)。

16

你可以看看 Django / Comet (Push): 最小的恶行? 或者 Python中Comet的最新推荐? - COMET其实就是“ajax长轮询”的另一种说法。

看起来最常见的方法不是直接在django里做,而是借助一个额外的守护进程(可能是因为像Apache这样的服务器不太适合处理很多长连接)。现在,nodejs和socketio非常流行(而且它们甚至可以使用WebSockets) - 你只需要找到一个好的方法来在这两者之间传递数据。如果数据是单向的(比如只向所有连接的客户端广播),那么使用redis的发布/订阅队列也是个不错的选择。

不过, http://code.google.com/p/django-orbited/ 可能是最符合django风格的解决方案。

撰写回答