当数据值更改时,如何将redis PUBLISH / SUBSCRIBE与nodejs一起使用来通知客户端?


99

我正在使用NodeJS和Redis编写事件驱动的发布/订阅应用程序。我需要一个如何在Redis中的数据值更改时通知Web客户端的示例。

Answers:


123

OLD仅使用参考

依存关系

使用expresssocket.ionode_redis以及最后但并非最不重要的来自媒体fire 的示例代码

安装node.js + npm(非root)

首先,你应该(如果你还没有这样做还)安装的node.js + NPM在30秒(以正确的方式,因为你应该运行NPM作为):

echo 'export PATH=$HOME/local/bin:$PATH' >> ~/.bashrc
. ~/.bashrc
mkdir ~/local
mkdir ~/node-latest-install
cd ~/node-latest-install
curl http://nodejs.org/dist/node-latest.tar.gz | tar xz --strip-components=1
./configure --prefix=~/local
make install # ok, fine, this step probably takes more than 30 seconds...
curl http://npmjs.org/install.sh | sh

安装依赖项

安装node + npm后,应通过发出以下命令来安装依赖项:

npm install express
npm install socket.io
npm install hiredis redis # hiredis to use c binding for redis => FAST :)

下载样本

您可以从mediafire下载完整样本。

解压缩包

unzip pbsb.zip # can also do via graphical interface if you prefer.

拉链里面有什么

./app.js

const PORT = 3000;
const HOST = 'localhost';

var express = require('express');

var app = module.exports = express.createServer();

app.use(express.staticProvider(__dirname + '/public'));

const redis = require('redis');
const client = redis.createClient();

const io = require('socket.io');

if (!module.parent) {
    app.listen(PORT, HOST);
    console.log("Express server listening on port %d", app.address().port)

    const socket  = io.listen(app);

    socket.on('connection', function(client) {
        const subscribe = redis.createClient();
        subscribe.subscribe('pubsub'); //    listen to messages from channel pubsub

        subscribe.on("message", function(channel, message) {
            client.send(message);
        });

        client.on('message', function(msg) {
        });

        client.on('disconnect', function() {
            subscribe.quit();
        });
    });
}

./public/index.html

<html>
<head>
    <title>PubSub</title>
    <script src="/socket.io/socket.io.js"></script>
    <script src="/javascripts/jquery-1.4.3.min.js"></script>
</head>
<body>
    <div id="content"></div>
    <script>    
        $(document).ready(function() {
            var socket = new io.Socket('localhost', {port: 3000, rememberTransport: false/*, transports: ['xhr-polling']*/});
            var content = $('#content');

            socket.on('connect', function() {
            });

            socket.on('message', function(message){
                content.prepend(message + '<br />');
            }) ;

            socket.on('disconnect', function() {
                console.log('disconnected');
                content.html("<b>Disconnected!</b>");
            });

            socket.connect();
        });
    </script>
</body>
</html>

启动服务器

cd pbsb    
node app.js

启动浏览器

最好是如果您启动google chrome(因为有websockets支持,但不是必需的)。造访http://localhost:3000以查看示例(开始时您除了PubSub标题以外什么都看不到)。

但是在publish频道上pubsub您应该会看到一条消息。下面我们发布"Hello world!"到浏览器。

从./redis-cli

publish pubsub "Hello world!"

您为什么需要const client = redis.createClient()app.js的根目录?
Akasha 2012年

您根本不需要使用const。var也可以使用,也许我应该使用var,因为const仅在较新的javascript引擎中可用。此外,这条线确保我们已连接到本示例中使用的redis服务器。
Alfred

5
该示例非常旧,因此无法使用最新的socket.io/express模块​​,甚至可能不是node.js。我会尝试更新代码。此代码还有另一个巨大的问题,它为每个连接的用户打开了另一个Redis连接。那应该只启用。我必须先工作,但在此之后,我尝试更新代码。
Alfred 2012年

1
很好。我仍然认为仍有一些改进的余地,如果有时间我会上网。但是现在我真的很努力:$。
2012年

1
我认为subscribe.on应该是socket.on(“连接”)块的外部以避免多个订阅/
zubinmehta

26

这是一个没有太多依赖关系的简化示例。您仍然需要npm install hiredis redis

节点JavaScript:

var redis = require("redis"),
    client = redis.createClient();

client.subscribe("pubsub");
client.on("message", function(channel, message){
  console.log(channel + ": " + message);
});

...将其放入pubsub.js文件中并运行 node pubsub.js

在redis-cli中:

redis> publish pubsub "Hello Wonky!"
(integer) 1

应该显示:pubsub: Hello Wonky!在终端运行节点中!恭喜!

另外的4/23/2013:我还想指出一点,当客户端订阅发布/订阅频道时,它将进入订阅者模式,并且仅限于订阅者命令。您只需要创建其他Redis客户端实例。client1 = redis.createClient(), client2 = redis.createClient()因此一个可以处于订户模式,另一个可以发出常规的DB命令。


在这里,当我们向Redis添加数据时,是否应该运行publish pubsub以获得插入通知?
IshaS 2015年

1
@IshaS,如果那是您需要做的,是的。如果您需要自动运行多个命令,还应该研究事务:redis.io/commands/exec
nak

@nak这就像在一个GO中一样具有魅力:)如果尚未安装“双端队列”,则某些用户可能需要安装。
Alex

1
还值得一提的是,如果你想使用通配符,例如,订阅pubsub/*只需添加p到例如:更换subscibepsubscribemessagepmessage
Liosha Bakoushin

7

完整的 Redis发布/ 订阅示例(使用Hapi.js和Socket.io 进行实时聊天

我们试图理解Redis的发布/订阅(“ 发布/订阅 ”)和所有现有的例子要么过时,过于简单或没有测试。因此,我们使用了Hapi.js + Socket.io + Redis Pub / Sub示例以及端到端测试,编写了一个完整的实时聊天

https://github.com/dwyl/hapi-socketio- redis-chat-example

Pub / Sub组件仅是几行node.js代码:https : //github.com/dwyl/hapi-socketio-redis-chat-example/blob/master/lib/chat.js#L33-L40

与其将其粘贴到此处(没有任何上下文),我们不建议您签出/尝试该示例

我们使用Hapi.js构建了该chat.js文件,但该文件已 Hapi分离,可以轻松地与基本的 node.js http服务器express(等)一起使用。


你有快递这个例子吗?
Gixty 2015年

@Gixty我们使用Hapi.js编写了该示例,因为那里的所有其他示例都使用Express.js ...如后文所述,将其移植到任何其他Node.js框架很简单(只需在express app /中传递侦听chat.js初始化代码),其工作原理完全相同。ps:如果您不熟悉Hapi.js,请参阅:github.com/nelsonic/learn-hapi
nelsonic 2015年

4

处理redis错误以阻止nodejs退出。您可以通过编写来完成;

subcribe.on("error", function(){
  //Deal with error
})

我认为您会收到例外,因为您使用的是订阅发布消息的相同客户端。创建一个单独的客户端来发布消息,这可以解决您的问题。



2

如果要使用socket.io 0.7 外部Web服务器,则需要进行更改(除了staticProvider-> static问题):

a)在index.html中提供域名而不是localhost(即var socket = io.connect('http://my.domain.com:3000');)

b)在app.js中更改主机(即const HOST ='my.domain.com';)

c)并在app.js的第37行中添加套接字(即'socket.sockets.on('connection',function(client){…'))



0

根据@alex解决方案。如果您有这样的错误,请按照@tyler提及:

node.js:134
        throw e; // process.nextTick error, or 'error'

event on first tick ^ Error: Redis connection to 127.0.0.1:6379 failed - ECONNREFUSED, Connection refused at Socket.

那么您需要先安装Redis。看一下这个:

http://redis.io/download

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.