NodeJS e PHP, just for fun

In questi giorni sto cercando di approfondire la conoscenza di Node.js ed ho iniziato con questo ottimo tutorial, veramente ben fatto.
Ovviamente, da bravo smanettone, dopo le prime N pagine mi sembrava di aver preso possesso dei concetti base e che fosse arrivato il momento di passare a qualche esempio "utile".
Ovviamente sono iniziate le grane...
Poiché sviluppo principalmente in PHP la mia idea era questa: realizzare con Node.js una sorta di dispatcher di eventi, per sostituire il long polling Ajax, lasciando la logica associata agli eventi negli script PHP.
Ho cominciato a cercare articoli e tutorial in rete e qualcosa ho combinato :)
Punto di partenza questo ottimo spunto di Gianluca Guarini, che implementa un push notification server con Node.js e socket.io; in pratica un semplice script Node.js gestisce la comunicazione con il client tramite websocket.
Partendo da questo schema ho aggiunto la possibilità di richiamare un servizio scritto in PHP, in risposta ad un evento intercettato da Node.js, tramite chiamata asincrona con jQuery.
L'unico vero problema incontrato è che il server Node.js sta in ascolto su una porta diversa da quella utilizzata da Apache per esporre i servizi scritti in PHP e quindi il browser blocca la comunicazione a causa della protezione per il cross domain scripting.
Per evitare questo inconveniente sono possibili 2 strade:
  1. usare mod_rewrite per mascherare le richieste a Node.js come descritto qui, oppure sfruttare mod_proxy (esempio qui );
  2. utilizzare JSONP per le chiamate Ajax.
Siccome la soluzione 1 non richiede alcuna modifica al codice mi sono divertito ad implementare la 2, garzie alle dritte che ho trovato in questo post.

Dopo qualche tentativo ecco il frutto delle mie fatiche ( ovviamente sono pigro e c'è un bel mix dei vari script, un po' in inglese, un po' in italiano :P ).

echo_service.php
1:  <?php  
2:  header("content-type: application/json");  
3:  echo $_GET['jsonp_callback']. '('. json_encode($_GET['message'].' alle '. Date("H:i:s")) . ')';   
4:  ?>  

server.js
1:  var http = require('http')  
2:  , url = require('url')  
3:  , fs = require('fs')  
4:  , server;  
5:  server = http.createServer(function(req, res){  
6:    // your normal server code  
7:    var path = url.parse(req.url).pathname;  
8:    switch (path){  
9:      case '/':  
10:        res.writeHead(200, {'Content-Type': 'text/html'});  
11:        res.write('<h1>Hello! Try the <a href="/socketio-test.html">Socket.io Test</a></h1>');  
12:        res.end();  
13:        break;  
14:      case '/socketio-test.html':  
15:        fs.readFile(__dirname + path, function(err, data){  
16:        if (err) return send404(res);  
17:        res.writeHead(200, {'Content-Type': path == 'json.js' ? 'text/javascript' : 'text/html'})  
18:        res.write(data, 'utf8');  
19:        res.end();  
20:        });  
21:        break;  
22:      default: send404(res);  
23:    }  
24:  }),  
25:  send404 = function(res){  
26:    res.writeHead(404);  
27:    res.write('404');  
28:    res.end();  
29:  };  
30:  server.listen(8080);  
31:  // socket.io, I choose you  
32:  var io = require('socket.io').listen(server);  
33:  // on a 'connection' event  
34:  io.sockets.on('connection', function(socket){  
35:   console.log("Connection " + socket.id + " accepted.");  
36:   // now that we have our connected 'socket' object, we can   
37:   // define its event handlers  
38:   socket.on('message', function(message){  
39:      console.log("Received message: " + message + " - from client " + socket.id);  
40:      socket.emit( 'message', 'Messaggio ricevuto');  
41:   });  
42:   socket.on('disconnect', function(){  
43:    console.log("Connection " + socket.id + " terminated.");  
44:   });  
45:  });  

socketio_test.html
1:  <!doctype html>  
2:  <html>  
3:   <head>  
4:    <title>Socket.io Test</title>  
5:    <script src="/socket.io/socket.io.js"></script>  
6:    <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>  
7:   </head>  
8:   <body>  
9:    <script>  
10:    var socket;  
11:    var firstconnect = true;  
12:    function connect() {  
13:     if(firstconnect) {  
14:      socket = io.connect(null);  
15:      socket.on('message', function(data){ message(data); });  
16:      socket.on('connect', function(){ status_update("Connected to Server"); });  
17:      socket.on('disconnect', function(){ status_update("Disconnected from Server"); });  
18:      socket.on('reconnect', function(){ status_update("Reconnected to Server"); });  
19:      socket.on('reconnecting', function( nextRetry ){ status_update("Reconnecting in "   
20:       + nextRetry + " seconds"); });  
21:      socket.on('reconnect_failed', function(){ message("Reconnect Failed"); });  
22:      firstconnect = false;  
23:     }  
24:     else {  
25:      socket.socket.reconnect();  
26:     }  
27:    }  
28:    function disconnect() {  
29:     socket.disconnect();  
30:    }  
31:    function message(data) {  
32:      $.ajax({  
33:        dataType: 'jsonp',  
34:        data: 'message=' + data,  
35:        jsonp: 'jsonp_callback',  
36:        jsonpCallback: 'jsonpcallback',  
37:        url: 'http://<your_apache_root>/echo_service.php'  
38:      });      
39:    }  
40:    function jsonpcallback( rtndata ) {  
41:      $('#message').html( rtndata );  
42:    }  
43:    function status_update(txt){  
44:     document.getElementById('status').innerHTML = txt;  
45:    }  
46:    function esc(msg){  
47:     return msg.replace(/</g, '&lt;').replace(/>/g, '&gt;');  
48:    }  
49:    function send() {  
50:     socket.send("Hello Server!");    
51:    };      
52:    </script>  
53:    <h1>Socket.io Test</h1>  
54:    <div><p id="status">Waiting for input</p></div>  
55:    <div><p id="message"></p></div>   
56:    <button id="connect" onClick='connect()'/>Connect</button>  
57:    <button id="disconnect" onClick='disconnect()'>Disconnect</button>  
58:    <button id="send" onClick='send()'/>Send Message</button>  
59:   </body>  
60:  </html>  

Commenti

Post popolari in questo blog

Jolie on Azure Functions

Gateway Consorzio Triveneto per WP e-commerce

Jolie micro services on Kubernetes