จะใช้ redis PUBLISH / SUBSCRIBE กับ nodejs เพื่อแจ้งลูกค้าเมื่อค่าข้อมูลเปลี่ยนแปลงได้อย่างไร


99

ฉันกำลังเขียนแอปพลิเคชันเผยแพร่ / สมัครสมาชิกตามเหตุการณ์ด้วย NodeJS และ Redis ฉันต้องการตัวอย่างวิธีแจ้งเว็บไคลเอนต์เมื่อค่าข้อมูลใน Redis เปลี่ยนแปลง

คำตอบ:


123

OLD ใช้ข้อมูลอ้างอิงเท่านั้น

การพึ่งพา

ใช้express , socket.io , node_redisและสุดท้าย แต่ไม่ท้ายสุดคือโค้ดตัวอย่างจากไฟไหม้สื่อ

ติดตั้ง node.js + npm (ไม่ใช่รูท)

ก่อนอื่นคุณควร (ถ้าคุณยังไม่ได้ทำ) ติดตั้ง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 :)

ดาวน์โหลดตัวอย่าง

คุณสามารถดาวน์โหลดตัวอย่างที่สมบูรณ์จากการโหลด

แพ็กเกจคลายซิป

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

คุณไม่จำเป็นต้องใช้ const เลย var สามารถใช้งานได้เช่นกันและบางทีฉันควรมีแทนเพราะ const มีให้ใช้งานในเอ็นจิ้นจาวาสคริปต์รุ่นใหม่เท่านั้น นอกจากนี้บรรทัดนี้ยังช่วยให้มั่นใจได้ว่าเราเชื่อมต่อกับเซิร์ฟเวอร์ redis ที่เราใช้ในตัวอย่างนี้
Alfred

5
ตัวอย่างนี้เก่ามากจึงไม่ทันสมัยกับโมดูล socket.io/express ล่าสุดและอาจจะเป็น node.js ฉันจะพยายามอัปเดตโค้ด นอกจากนี้ยังมีปัญหาใหญ่อีกประการหนึ่งเกี่ยวกับรหัสนี้ซึ่งจะเปิดการเชื่อมต่อ redis อื่นสำหรับผู้ใช้ที่เชื่อมต่อแต่ละคน ที่ควรจะเปิดแทน ฉันต้องทำงานก่อน แต่หลังจากนั้นฉันพยายามอัปเดตโค้ด
Alfred

1
ดีมาก. ฉันยังคิดว่ามีที่ว่างสำหรับการปรับปรุงบางอย่างซึ่งเมื่อฉันมีเวลาฉันจะออนไลน์ แต่ตอนนี้ฉันทำงานหนักมาก: $.
Alfred

1
ฉันคิดว่า subscribe.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:ฉันต้องการทราบด้วยว่าเมื่อลูกค้าสมัครสมาชิกช่อง pub / sub ระบบจะเข้าสู่โหมดสมาชิกและถูก จำกัด ไว้ที่คำสั่งของสมาชิก คุณจะต้องสร้างอินสแตนซ์เพิ่มเติมของไคลเอนต์ redis client1 = redis.createClient(), client2 = redis.createClient()เพื่อให้สามารถอยู่ในโหมดสมาชิกและอีกคนหนึ่งสามารถออกคำสั่ง DB ปกติได้


ที่นี่เมื่อเราเพิ่มข้อมูลลงใน redis ฉันควรเรียกใช้ pubsub เพื่อรับการแจ้งเตือนการแทรกหรือไม่
IshaS

1
@IshaS ถ้านั่นคือสิ่งที่คุณต้องทำใช่ คุณควรพิจารณาธุรกรรมด้วยหากคุณต้องการเรียกใช้คำสั่งหลายคำสั่ง atomically: redis.io/commands/exec
nak

@nak สิ่งนี้ใช้งานได้เหมือนมีเสน่ห์ใน GO เดียว :) ผู้ใช้บางรายอาจต้องติดตั้ง 'double-ended-que' หากยังไม่ได้ติดตั้ง
Manjeet

1
นอกจากนี้ยังคุ้มค่าที่จะพูดถึงว่าถ้าคุณต้องการที่จะใช้สัญลักษณ์แทนตัวอย่างเช่นสมัครเป็นสมาชิกpubsub/*เพียงแค่เพิ่มpไปตัวอย่าง: แทนที่subscibeด้วยpsubscribeและมีmessage pmessage
Liosha Bakoushin

7

ทำตัวอย่าง Redis Pub / Sub ให้สมบูรณ์ ( แชทตามเวลาจริงโดยใช้ Hapi.js & Socket.io)

เราพยายามทำความเข้าใจ Redis Publish / Subscribe (" Pub / Sub ") และตัวอย่างทั้งหมดที่มีอยู่นั้นล้าสมัยเรียบง่ายเกินไปหรือไม่มีการทดสอบใด ๆ ดังนั้นเราจึงเขียนการแชทแบบเรียลไทม์ที่สมบูรณ์โดยใช้ Hapi.js + Socket.io + Redis Pub / Sub ตัวอย่างด้วย End-to-End Tests !

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ไฟล์de-ควบคู่ไปจากขั้นตอนที่สามารถได้อย่างง่ายดายใช้กับพื้นฐาน Node.js http เซิร์ฟเวอร์หรือแสดง (อื่น ๆ )


คุณมีตัวอย่างด่วนนี้ไหม
Gixty

@Gixty เราเขียนตัวอย่างโดยใช้ Hapi.js เพราะตัวอย่างอื่น ๆ ทั้งหมดใช้ Express.js ... ฟังรหัสเริ่มต้นของ chat.js) และทำงานเหมือนกันทุกประการ ps: ถ้าคุณยังใหม่กับ Hapi.js โปรดดู: github.com/nelsonic/learn-hapi
nelsonic

4

จัดการข้อผิดพลาด redis เพื่อหยุดการออกจาก nodejs คุณสามารถทำได้โดยการเขียน;

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

ฉันคิดว่าคุณได้รับข้อยกเว้นเนื่องจากคุณใช้ไคลเอนต์เดียวกันซึ่งสมัครรับข้อมูลเพื่อเผยแพร่ข้อความ สร้างไคลเอนต์แยกต่างหากสำหรับการเผยแพร่ข้อความและสามารถแก้ปัญหาของคุณได้



2

หากคุณต้องการให้สิ่งนี้ทำงานกับ socket.io 0.7 และเว็บเซิร์ฟเวอร์ภายนอกคุณต้องเปลี่ยน (นอกเหนือจาก staticProvider -> ปัญหาคงที่):

ก) ระบุชื่อโดเมนแทน localhost (เช่น var socket = io.connect ('http://my.domain.com:3000');) ใน index.html

b) เปลี่ยน HOST ใน app.js (เช่น const HOST = 'my.domain.com';)

c) และเพิ่มซ็อกเก็ตในบรรทัดที่ 37 ของ app.js (เช่น '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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.