Django:使用 Redis PubSub、Node.js 和 Socket.io 的 JSON 通知



我看到了这篇文章:http://maxburstein.com/blog/realtime-django-using-nodejs-and-socketio/

这把我引向了一个有点正确的方向。

我目前有一个iOS前端和一个Django后端。我使用Gunicorn为前端应用程序提供数据。我的iOS应用程序和我的后台之间的通信是基于REST的。我只是来回发送JSON。我不提供任何网页。只是JSON响应。

我实现了一个简单的Post&评论模型:

class Post(models.Model):
user = models.ForeignKey(User)
blog = models.CharField(max_length=5000)
class Comment(models.Model):
comment = models.CharField(max_length=140)
user = models.ForeignKey(User)
post_id = models.ForeignKey(Post)
created_at = models.DateTimeField(auto_now_add=True)

用户可以发表博客文章,其他用户可以对此发表评论。所以,如果用户X有一篇博客文章和用户Y的评论。我想通知用户X,用户Y对他/她的帖子发表了评论。

我曾经依靠pyAPNS来通知用户;一个使用Twisted向APNS发送通知的python包装器,但如果userX关闭了我的应用程序的推送通知,那么userX将无法接收应用程序内通知。所以我运气不好。

我只关心应用内通知。我仍然希望用户X在应用程序中时能收到实时更新。

当用户发出POST请求时,Django可以将消息发布到Redis上的通道。Node.js会订阅该频道,socket.io会将其发送给该特定用户。

这是我的views.py的精简版本,其中创建了注释对象。我将id发送给发表评论的用户、帖子的id和发表博客的用户。用户将使用json对此url发出post请求:http://example.com:8000/upload-评论/

def UploadComment(request):
data  = json.loads(request.body)
redis_server = redis.Redis(host='12.345.678.9', port=6379, db=0, password='mypassword')
newComment = Comment()
newComment.comment = data['comment']
newComment.user_id = data['user_id']
newComment.post_id = data['post_id']
newComment.save() 
PostOwner = data['post_owner_id'] #id of the blog post owner
# Need to send a notification to PostOwner
response_data = []
response_data.append(
{'send_notifcation_to': PostOwner
'action': 'comment'
'comment_by': newComment.user.username)}
redis_server.publish("notifications", json.dumps(response_data))
return HttpResponse('Request Successful')

Node.js的实现(根据Max Burstein的文章)

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

就我所知:(我知道这很可悲,但我还有很多问题。我如何将node.js订阅到我从Django发布到的远程Redis服务器?有多少客户端可以连接到这个套接字?有限制吗?是为每个客户端创建一个套接字吗?还是每个客户端都在同一个套接字上侦听?我可以通过这个套接字将json数据发送到一个特定的客户端吗?我知道这是一个巨大的帖子,但我急需帮助。如果我有什么不清楚的地方,请告诉我,这样我就可以编辑这个问题了。非常感谢。

我绝对不会为此使用node.js。使用Celery或gevent或其他任何工具,您都可以很好地处理Python中的websocket。

只需创建一个注册到Redis并侦听新消息的线程。

当用户连接时,将套接字放入由用户名索引的弱值哈希中;当他们的消息到达时,在该哈希中查找目标用户名并将其发送出去。弱值是因为当用户断开连接时,它会自行清理。真的很简单。

我也会使用websocket而不是HTTP-PUT向服务器发送新消息。

看看这里的实现:http://blog.sneawo.com/blog/2013/02/08/real-time-messaging-in-django-using-node-dot-js-and-redis/

听起来应该使用类似RabbitMQ的东西http://www.rabbitmq.com/devtools.html有一个node.js实现等等。

看看吧,它应该会让你高兴起来:)

我还使用了一个很棒的库,名为django-websocket-redis。

虽然它不使用gunicorn,但它使用了uWSGI,这在迁移到时应该不会有太多开销。只需遵循文档,它们非常全面。

https://django-websocket-redis.readthedocs.org/en/latest/

获取一些代码并使用django websockets redis:实现

## Make a json representation of your model available.
class Comment(models.Model):
comment = models.CharField(max_length=140)
user = models.ForeignKey(User)
post_id = models.ForeignKey(Post)
created_at = models.DateTimeField(auto_now_add=True)
def as_json(self):
return dict(
id=self.id,
comment=self.comment,
created_at=self.created_at.strftime('%m/%d/%Y'),
post_id=self.post_id
user=self.user
)

然后,在您的视图中,当发出请求时,将json表示保存到您订阅的redis工具中……您可以在任何地方执行此操作,无论是您的序列化程序还是视图,但我将由您决定。

def UploadComment(request):
data  = json.loads(request.body)
## In django-websockets-redis, this portion below is registered in the settings.py file, therefore i am commenting this out. 
## redis_server = redis.Redis(host='12.345.678.9', port=6379, db=0, password='mypassword')
newComment = Comment()
newComment.comment = data['comment']
newComment.user_id = data['user_id']
newComment.post_id = data['post_id']
newComment.save() 
PostOwner = data['post_owner_id'] #id of the blog post owner
# Need to send a notification to PostOwner
## Need to turn this into a string before posting to redis
json_comment = str(newComment.as_json())
## Create a facility based on the PostOwner ID. The PostOwner will always be subscribed to this channel. 
RedisPublisher(facility=PostOwner, broadcast=True).publish_message(json_comment)
return HttpResponse('Request Successful')

现在我们已经处理好了后端,在前端visa vie JavaScript上,您的用户根据他的user.id:订阅设施

jQuery(document).ready(function($) {
var ws4redis = WS4Redis({
uri: '{{ WEBSOCKET_URI }}{{ PostOwner.id }}?subscribe-broadcast&publish-broadcast&echo',
receive_message: receiveMessage,
heartbeat_msg: {{ WS4REDIS_HEARTBEAT }}
});
// receive a message though the Websocket from the server
function receiveMessage(msg) {
//This is where you would retrieve the JSON string from the Redis server, and subsequently manipulate the DOM with appends, Toastr Notifications, Etc...
}

最新更新