Bagaimana cara menggunakan redis PUBLISH / SUBSCRIBE with nodejs untuk memberi tahu klien saat nilai data berubah?

99

Saya sedang menulis aplikasi publikasi / langganan yang digerakkan oleh peristiwa dengan NodeJS dan Redis. Saya memerlukan contoh cara memberi tahu klien web saat nilai data di Redis berubah.

guilin 桂林
sumber

Jawaban:

123

LAMA hanya menggunakan referensi

Dependensi

menggunakan express , socket.io , node_redis dan yang terakhir tetapi tidak kalah pentingnya kode sampel dari api media.

Instal node.js + npm (sebagai non root)

Pertama Anda harus (jika Anda belum melakukannya) menginstal node.js + npm dalam 30 detik (cara yang benar karena Anda TIDAK harus menjalankan npm sebagai root ):

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

Instal dependensi

Setelah Anda menginstal node + npm, Anda harus menginstal dependensi dengan menerbitkan:

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

Unduh sampel

Anda dapat mengunduh sampel lengkap dari mediafire .

Buka zip paket

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

Apa yang ada di dalam zip

./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>

Mulai server

cd pbsb    
node app.js

Mulai browser

Paling baik jika Anda memulai google chrome (karena dukungan websockets, tetapi tidak perlu). Kunjungi http://localhost:3000untuk melihat sampel (pada awalnya Anda tidak melihat apa pun kecualiPubSub sebagai judul).

Tapi di publishsaluran pubsubAnda akan melihat pesan. Di bawah ini kami publikasikan "Hello world!"ke browser.

Dari ./redis-cli

publish pubsub "Hello world!"
Alfred
sumber
mengapa Anda membutuhkan const client = redis.createClient()di root app.js?
Akasha
Anda tidak perlu menggunakan const sama sekali. var dapat digunakan juga dan mungkin saya harus menggunakannya karena const hanya tersedia di mesin javascript yang lebih baru. Selanjutnya baris ini memastikan kita terhubung ke server redis yang kita gunakan dalam contoh ini.
Alfred
5
Sampelnya sangat tua jadi tidak up-to-date dengan modul socket.io/express terbaru dan bahkan mungkin node.js. Saya akan mencoba memperbarui kode. Ada juga masalah besar lainnya dengan kode ini yang membuka koneksi redis lain untuk setiap pengguna yang terhubung. Itu seharusnya hanya aktif. Saya harus bekerja dulu, tetapi setelah itu saya mencoba memperbarui kode.
Alfred
1
Baik sekali. Saya masih berpikir masih ada ruang untuk beberapa perbaikan yang ketika saya punya waktu saya akan online. Tapi sekarang saya benar-benar bekerja keras: $.
Alfred
1
Saya pikir subscribe.on harus berada di luar blok socket.on ('koneksi') untuk menghindari banyak pelanggan /
zubinmehta
26

berikut adalah contoh sederhana tanpa banyak ketergantungan. Anda masih perlu melakukannyanpm install hiredis redis

Node JavaScript:

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

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

... taruh itu di file pubsub.js dan jalankan node pubsub.js

di redis-cli:

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

yang seharusnya menampilkan: pubsub: Hello Wonky!di terminal yang menjalankan node! Selamat!

Tambahan 4/23/2013: Saya juga ingin mencatat bahwa ketika klien berlangganan ke saluran pub / sub, ia masuk ke mode pelanggan dan terbatas pada perintah pelanggan. Anda hanya perlu membuat instance tambahan dari klien redis. client1 = redis.createClient(), client2 = redis.createClient()jadi satu bisa dalam mode pelanggan dan yang lain bisa mengeluarkan perintah DB biasa.

nak
sumber
Di sini, ketika kami menambahkan data ke redis, haruskah saya menjalankan publish pubsub untuk mendapatkan pemberitahuan penyisipan?
IshaS
1
@IsaS kalau itu yang perlu kamu lakukan, ya. Anda juga harus melihat transaksi jika Anda perlu menjalankan beberapa perintah secara atomik: redis.io/commands/exec
nak
@nak Ini bekerja seperti pesona dalam satu GO :) Beberapa pengguna mungkin perlu menginstal 'antrian ganda' jika belum diinstal.
Alex
1
Perlu juga disebutkan bahwa jika Anda ingin menggunakan wildcard, misalnya, berlangganan pubsub/*hanya menambahkan pke contoh: ganti subscibedengan psubscribedan messagedengan pmessage.
Liosha Bakoushin
7

Contoh Lengkap Redis Pub / Sub ( Obrolan Waktu Nyata Nyata menggunakan Hapi.js & Socket.io)

Kami mencoba memahami Redis Publish / Subscribe (" Pub / Sub ") dan semua contoh yang ada sudah usang, terlalu sederhana atau tidak memiliki pengujian. Jadi kami menulis Obrolan Waktu Nyata Lengkap menggunakan Hapi.js + Socket.io + Contoh Redis Pub / Sub dengan Tes End-to-End !

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

Komponen Pub / Sub hanya beberapa baris kode node.js: https://github.com/dwyl/hapi-socketio-redis-chat-example/blob/master/lib/chat.js#L33-L40

Daripada menempelkannya di sini ( tanpa konteks apa pun ), kami mendorong Anda untuk membayar / mencoba contoh .

Kami membangunnya menggunakan Hapi.js tetapi chat.jsfile de-ditambah dari Hapi dan dapat dengan mudah digunakan dengan dasar server yang node.js http atau mengungkapkan (dll)

nelsonic
sumber
apakah Anda memiliki contoh ini dengan express?
Gixty
@Gixty kami menulis contoh menggunakan Hapi.js karena semua contoh lain di luar sana menggunakan Express.js ... seperti yang disebutkan dalam posting, sepele untuk mem -port-nya ke kerangka kerja Node.js lainnya (cukup teruskan di aplikasi ekspres / listener ke kode init chat.js) dan berfungsi persis sama. ps: jika Anda baru mengenal Hapi.js lihat: github.com/nelsonic/learn-hapi
nelsonic
4

Tangani error redis untuk menghentikan nodej agar tidak keluar. Anda dapat melakukannya dengan menulis;

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

Saya rasa Anda mendapatkan pengecualian karena Anda menggunakan klien yang sama yang berlangganan untuk menerbitkan pesan. Buat klien terpisah untuk menerbitkan pesan dan itu bisa menyelesaikan masalah Anda.

Awemo
sumber
2

Jika Anda ingin membuatnya berfungsi dengan socket.io 0.7 DAN server web eksternal, Anda perlu mengubah (selain staticProvider -> masalah statis):

a) berikan nama domain sebagai ganti localhost (yaitu var socket = io.connect ('http://my.domain.com:3000');) di index.html

b) ubah HOST di app.js (yaitu, const HOST = 'domainku.com';)

c) dan tambahkan soket di baris 37 app.js (yaitu 'socket.sockets.on (' connection ', function (client) {…')

dirkk0
sumber
1

Perbarui ke kode:

staticProvider

sekarang berganti nama menjadi

statis

lihat panduan migrasi

Alex Mikhalev
sumber
0

menurut solusi @alex . jika Anda memiliki kesalahan seperti ini sesuai @tyler menyebutkan:

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.

maka Anda perlu menginstal Redis terlebih dahulu. lihat ini:

http://redis.io/download

hbinduni
sumber