Come integrare nodeJS + Socket.IO e PHP?


98

Recentemente mi sono guardato intorno, per trovare un buon modo per comunicare tra nodeJS e PHP. Ecco l'idea: nodeJS è ancora abbastanza nuovo e può essere un po 'complicato sviluppare un'applicazione completa solo con esso. Inoltre, potresti averne bisogno solo per un modulo del tuo progetto, come notifiche in tempo reale, chat, ... E vuoi gestire tutte le altre cose con PHP, perché probabilmente è più facile per te (e puoi sfruttare i framework esistenti, come CodeIgniter o Symfony).

Vorrei avere una soluzione facile; Non voglio usare cURL o un terzo server per comunicare tra i server Apache e Node. Quello che voglio è essere in grado di catturare gli eventi dal nodo in semplice Javascript, lato client.

Non ho trovato alcuna risposta che, se completa, la maggior parte delle volte lato client era in esecuzione dal server del nodo e quindi non applicabile nel mio caso. Così ho strisciato tutti gli argomenti possibili e finalmente ho trovato la mia risposta; Cercherò di condividere questo e di avere un punto in cui è tutto chiaro.

Spero che questo possa aiutare alcune persone! ;)

Risposte:


131

Quindi, per cominciare, metto il mio progetto su GitHub, se vuoi accedere al codice completo: https://github.com/jdutheil/nodePHP

È un progetto di esempio molto semplice: una chat web. Hai solo un autore e un messaggio e quando premi invia viene salvato in un database mysql. L'idea è di inviare aggiornamenti in tempo reale e avere una vera conversazione. ;) Useremo nodeJS per questo.

Non parlerò del codice PHP, è davvero semplice e non interessante qui; quello che voglio mostrarti è come integrare il tuo codice nodeJS.

Io uso express e Socket.IO, quindi assicurati di installare quei moduli con npm. Quindi, creiamo un semplice server nodeJS:

var socket = require( 'socket.io' );
var express = require( 'express' );
var http = require( 'http' );

var app = express();
var server = http.createServer( app );

var io = socket.listen( server );

io.sockets.on( 'connection', function( client ) {
    console.log( "New client !" );

    client.on( 'message', function( data ) {
        console.log( 'Message received ' + data.name + ":" + data.message );

        io.sockets.emit( 'message', { name: data.name, message: data.message } );
    });
});

server.listen( 8080 );

Abbiamo registrato la richiamata degli eventi quando un nuovo utente è connesso; ogni volta che riceviamo un messaggio (rappresenta un messaggio di chat), lo trasmettiamo a tutti gli utenti collegati. Ora, la parte difficile: lato client! Questa è la parte che mi ha richiesto la maggior parte del tempo, perché non sapevo quale script includere per poter eseguire il codice Socket.IO senza il nodeServer (perché la pagina client sarà servita da Apache).

Ma tutto è già fatto; quando installi il modulo Socket.IO con npm, uno script è disponibile in /node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js; che lo script includeremo nella nostra pagina PHP, nel mio caso:

    <script src="js/node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js"></script>
    <script src="js/nodeClient.js"></script>

E per finire, il mio nodeClient.js, dove ci colleghiamo semplicemente al server del nodo e aspettiamo che l'evento aggiorni la nostra pagina. ;)

var socket = io.connect( 'http://localhost:8080' );

$( "#messageForm" ).submit( function() {
    var nameVal = $( "#nameInput" ).val();
    var msg = $( "#messageInput" ).val();

    socket.emit( 'message', { name: nameVal, message: msg } );

    // Ajax call for saving datas
    $.ajax({
        url: "./ajax/insertNewMessage.php",
        type: "POST",
        data: { name: nameVal, message: msg },
        success: function(data) {

        }
    });

    return false;
});

socket.on( 'message', function( data ) {
    var actualContent = $( "#messages" ).html();
    var newMsgContent = '<li> <strong>' + data.name + '</strong> : ' + data.message + '</li>';
    var content = newMsgContent + actualContent;

    $( "#messages" ).html( content );
});

Cercherò di aggiornare e migliorare il mio codice il prima possibile, ma penso che sia già aperto a tutte le cose interessanti! Sono davvero disponibile per consigli e recensioni su questa roba, è un buon modo per farlo, ..?

Spero che questo possa aiutare alcune persone!


18
Bene, quando scrivi una domanda c'è un'opzione "rispondi alla tua domanda, condividi la conoscenza stile di domande e risposte", quindi ho pensato che possiamo condividere in questo modo, scusa se sbaglio :)
Jérémy Dutheil

4
Come suggerimento, penso che incorporare la risposta a questa domanda qui stackoverflow.com/questions/5818312/mysql-with-node-js sia un metodo superiore. evitando qualsiasi chiamata ajax e rendendo il codice più in linea con l'uso di node. Ora, PHP può semplicemente selezionare le informazioni dal database.
blackmambo

1
È possibile connettersi all'app del nodo utilizzando io.connect se si trova su una macchina diversa dalla tua app principale piuttosto che avere l'app del nodo sullo stesso server ma utilizzando una porta diversa?
maembe

1
richiedono la firma hmac come autenticazione del messaggio. questo assicura che solo php possa trasmettere messaggi al socket. il socket ispezionerà il token firmato e, se passa, ti trasmetterà il messaggio. questo è utile per prevenire lo spam e garantire l'integrità dei dati. quindi non inviare mai direttamente al socket del nodo dal client. invece posta nell'app php con ajax, quindi inoltralo al server socket. è abbastanza non banale aprire una connessione socket a un server websocket con fopen + fwrite o stream select da php.
r3wt

1
D'accordo con @Bangash, puoi usare Node.js per memorizzare i dati nel database mysql invece di PHP, il che lo renderebbe molto più veloce
Parthapratim Neog

2

Ho un'altra soluzione che funziona abbastanza bene per me, ma vorrei che qualcuno commentasse quanto sia efficace, poiché non ho (ancora) avuto l'opportunità / tempo di testarla sul server reale.

Ecco il codice node-js. Ho inserito questo codice in un file chiamato nodeserver.js:

var http = require('http');

http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/html'});

    var knall = new Object();
    knall.totten = "4 tomtar";
    knall.theArr = new Array();
    knall.theArr.push("hoppla")
    knall.theArr.push("hej")
    var strKnall = JSON.stringify(knall);

    res.end(strKnall);
}).listen(process.env.PORT);  

Ed ecco il semplice pezzo di codice in php, che chiama il server node-js con l'aiuto di file_get_contents ():

$json = file_get_contents('http://localhost:3002/knall.json');
$obj = json_decode($json);

Funziona alla grande, quando carico la pagina php, a sua volta richiama la pagina nodeserver.js, che jsonifica l'oggetto knall.

Ho due installazioni localhost in esecuzione su iis su Windows 10, un server php standard e il server nodejs funziona con il pacchetto iisnode pulito .

Il server "reale" viene eseguito su Ubuntu.

Penso che questa sia una soluzione semplice e chiara per la comunicazione tra due server, ma forse qualcuno ha dei commenti al riguardo?


Questo non ha senso per me, perché stai avviando il server del nodo dall'interno dello script php. Non riesco a immaginare alcun caso d'uso per questo. Ciò di cui abbiamo bisogno è un modo per comunicare tra un'istanza di node.js in esecuzione e php.
Lorenz Meyer

No @Lorenz, questo è lo script node.js, in esecuzione sul proprio server. Sto chiamando la pagina node.js direttamente da php con file_get_contents (), da un altro server php. Ora è di uso quotidiano con oltre 500 utenti al giorno. Forse sei confuso perché il pezzo "localhost: 3002"? Questo perché questo esempio viene eseguito sul mio computer Windows locale, con due server autonomi in iis.
Snorvarg

Sono veramente confuso. Ciò significa che in nodejs.jsrealtà non è un file sorgente, ma è un URL che hai chiamato così, perché contiene json? Il primo non avrebbe alcun senso, ma il secondo mi sembra molto confuso.
Lorenz Meyer

@ Lorenz, ho provato a chiarire l'esempio cambiando il nome del file nodejs js e modificando un po 'il testo. Per rispondere alla tua domanda, il file ora rinominato in nodeserver.js viene eseguito sul proprio server. La chiamata http.createServer () crea un server, che ascolta () le connessioni in entrata sulla porta 80.
Snorvarg

Nota che puoi chiamare il server node.js direttamente da un browser, inserendo semplicemente l'url " localhost: 3002 / nodeserver.js " e otterrai una risposta json. Il file_get_contents () nel file php recupera il contenuto da un altro server, in questo caso il server node.js.
Snorvarg

0

Prova simile o puoi controllare il mio blog per il codice di esempio completo su nodejs


Sul lato della tua pagina:

  • Load Socket JS

https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js

  • Fai oggetto della presa

var socket = io ();

  • Utilizza la emitfunzione per inviare i dati al nodeserver.

socket.emit ('new_notification', {
message: 'message',
title: 'title',
icon: 'icon',
});

Quindi ora il tuo codice apparirà come

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>

var socket = io(); 

$(document).ready(function($) {
  $('.rules-table').on('click', '.runRule', function(event) {
    event.preventDefault();
    /* Act on the event */
    var ruleID = $(this).parents('tr').attr('id');

    // send notification before going to post 
    socket.emit('new_notification', {
        message: 'Messge is ready to sent',
        title: title,
        icon: icon,
    });
    $.ajax({
      url: '/ajax/run-rule.php',
      type: 'POST',
      dataType: 'json',
      data: {
        ruleID: ruleID
      },
    })
    .done(function(data) {
      console.log(data);

      // send notification when post success 
      socket.emit('new_notification', {
        message: 'Messge was sent',
        title: title,
        icon: icon,
      });

    })
    .fail(function() {
      console.log("error");

      // send notification when post failed 
      socket.emit('new_notification', {
        message: 'Messge was failed',
        title: title,
        icon: icon,
      });
    })
    .always(function() {
      console.log("complete");
    });

  });
});

Ora sul lato server del nodo, crea un gestore per la tua richiesta per ottenere la tua richiesta e inviare un messaggio a tutti i dispositivi / browser collegati (server.js)

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

app.get('/', function(req, res) {
   res.sendfile('index.html');
});


io.on('connection', function (socket) {
  socket.on( 'new_notification', function( data ) {
    console.log(data.title,data.message);

    // Now Emit this message to all connected devices
    io.sockets.emit( 'show_notification', { 
      title: data.title, 
      message: data.message, 
      icon: data.icon, 
    });
  });
});

http.listen(3000, function() {
   console.log('listening on localhost:3000');
});

Ora il lato client / browser / client crea un ricevitore per ricevere il messaggio socket dal server del nodo

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>   

var socket = io();

/**
 * Set Default Socket For Show Notification
 * @param {type} data
 * @returns {undefined}
 */
socket.on('show_notification', function (data) {
    showDesktopNotification(data.title, data.message, data.icon);
});
/**
 * Set Notification Request
 * @type type
 */
function setNotification() {
    showDesktopNotification('Lokesh', 'Desktop Notification..!', '/index.jpeg');
    sendNodeNotification('Lokesh', 'Browser Notification..!', '/index.jpeg');
}
/**
 * Check Browser Notification Permission
 * @type window.Notification|Window.Notification|window.webkitNotification|Window.webkitNotification|Window.mozNotification|window.mozNotification
 */
var Notification = window.Notification || window.mozNotification || window.webkitNotification;
Notification.requestPermission(function (permission) {
});
/**
 * Request Browser Notification Permission 
 * @type Arguments
 */
function requestNotificationPermissions() {
    if (Notification.permission !== 'denied') {
        Notification.requestPermission(function (permission) {
        });
    }
}
/**
 * Show Desktop Notification If Notification Allow
 * @param {type} title
 * @param {type} message
 * @param {type} icon
 * @returns {undefined}
 */
function showDesktopNotification(message, body, icon, sound, timeout) {
    if (!timeout) {
        timeout = 4000;
    }
    requestNotificationPermissions();
    var instance = new Notification(
            message, {
                body: body,
                icon: icon,
                sound: sound
            }
    );
    instance.onclick = function () {
        // Something to do
    };
    instance.onerror = function () {
        // Something to do
    };
    instance.onshow = function () {
        // Something to do
    };
    instance.onclose = function () {
        // Something to do
    };
    if (sound)
    {
        instance.sound;
    }
    setTimeout(instance.close.bind(instance), timeout);
    return false;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.