Як інтегрувати nodeJS + Socket.IO і PHP?


98

Нещодавно я озирався, щоб знайти хороший спосіб спілкування між nodeJS та PHP. Ось ідея: nodeJS все ще досить нова, і розробити повний додаток лише з ним може бути дуже складно. Більше того, він вам може знадобитися лише для одного модуля вашого проекту, як сповіщення в режимі реального часу, чат, ... І ви хочете керувати всіма іншими речами за допомогою PHP, тому що це вам, мабуть, простіше (і ви можете скористатися цим існуючі рамки, такі як CodeIgniter або Symfony).

Я хотів би мати просте рішення; Я не хочу використовувати cURL або третій сервер для зв'язку між серверами Apache та Node. Те, що я хочу, - це вміти ловити події з вузла у простому Javascript на стороні клієнта.

Я не знайшов жодних відповідей, що там, де повно, більшість часу на стороні клієнта працює сервер вузлів і тому не застосовується в моєму випадку. Тож я переглянув усі можливі теми і нарешті знайшов свою відповідь; Я спробую поділитися цим і мати точку, де все зрозуміло.

Сподіваюся, це може допомогти деяким людям! ;)

Відповіді:


131

Отже, для початку я розміщую свій проект на github, якщо ви хочете отримати повний код: https://github.com/jdutheil/nodePHP

Це дуже простий приклад проекту: веб-чат. У вас просто є автор і повідомлення, і при натисканні надіслати його зберігається в базі даних mysql. Ідея полягає у тому, щоб надсилати оновлення в реальному часі та вести справжню розмову. ;) Для цього ми будемо використовувати nodeJS.

Я не буду говорити про PHP-код, він дійсно простий і не цікавий тут; що я хочу вам показати, як інтегрувати код nodeJS.

Я використовую express і Socket.IO, тому не забудьте встановити ці модулі з npm. Потім ми створюємо простий сервер 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 );

Ми зареєстрували зворотний виклик подій, коли підключено нового користувача; щоразу, коли ми отримуємо повідомлення (представляє повідомлення в чаті), ми передаємо його всім підключеним користувачам. Тепер, хитра частина: на стороні клієнта! Та частина, яка зайняла у мене більшу частину часу, тому що я не знав, до якого сценарію можна запустити код Socket.IO без nodeServer (адже сторінку клієнта обслуговуватиме Apache).

Але все вже зроблено; при встановленні модуля Socket.IO з npm, сценарій доступний у /node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js; що сценарій, який ми будемо включати в нашу сторінку PHP, в моєму випадку:

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

І закінчуючи, мій nodeClient.js, де ми просто підключаємося до сервера вузлів і чекаємо події, щоб оновити нашу сторінку. ;)

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 );
});

Я спробую якомога швидше оновити та вдосконалити свій код, але, думаю, він уже відкритий для всіх крутих речей! Я дійсно відкритий для порад та відгуків щодо цього матеріалу, чи це хороший спосіб зробити це, ..?

Сподіваюся, це може допомогти деяким людям!


18
Що ж, коли ви пишете запитання, є варіант "відповісти на власне запитання, поділитися знаннями Q&A стиль", тому я подумав, що ми можемо поділитися таким, вибачте, якщо я помиляюся :)
Jérémy Dutheil

4
В якості пропозиції я думаю, що включення відповіді на це запитання тут stackoverflow.com/questions/5818312/mysql-with-node-js є вищим методом. уникаючи будь-якого виклику Ajax та робить код більш вбудованим із використанням вузла. Тепер PHP може просто вибрати інформацію з бази даних.
blackmambo

1
Чи можливо підключитися до додатка вузла за допомогою io.connect, якщо він працює на іншій машині, ніж у вашому головному додатку, а не у тому, що додаток вузла на тому ж сервері, але використовується інший порт?
maembe

1
вимагають підписання hmac як автентифікації повідомлення. це гарантує, що лише php може транслювати повідомлення в сокет. сокет перевіряє підписаний маркер, і якщо він пройде, ти передасть повідомлення. це добре для запобігання спаму та забезпечення цілісності даних. тому ніколи не публікуйте безпосередньо у сокет вузла від клієнта. замість цього розміщуйте у програмі php з ajax, а потім передайте це на сервер сокет. досить нетривіально відкривати з'єднання з сокетом до сервера websocket з fopen + fwrite або stream select з php.
r3wt

1
За погодженням з @Bangash, ви можете використовувати Node.js для зберігання даних у mysql db замість PHP, що зробить це набагато швидше
Parthapratim Neog

2

У мене є ще одне рішення, яке працює для мене досить добре, але я хотів би, щоб хтось прокоментував, наскільки це ефективно, оскільки я ще (ще) не мав можливості / часу перевірити його на реальному сервері.

Тут іде код node-js. Я ставлю цей код у файл під назвою 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);  

А ось простий фрагмент коду в php, виклик сервера node-js за допомогою file_get_contents ():

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

Чудово працює, коли я завантажую php-сторінку, вона, в свою чергу, викликає сторінку nodeserver.js, яка jsonify knall-object.

У мене є два localhost-установки, які працюють на iis на Windows 10, один стандартний php-сервер, а сервер nodejs працює з акуратним пакетом iisnode .

"Справжній" сервер працює на ubuntu.

Я думаю, що це акуратне і просте рішення для зв'язку між двома серверами, але, можливо, хтось має коментарі до цього?


Це не має для мене сенсу, оскільки ви запускаєте сервер вузлів зсередини php-скрипту. Я не можу уявити жодного випадку використання для цього. Нам потрібен спосіб спілкування між запущеним екземпляром node.js та php.
Лоренц Мейєр

Ні @Lorenz, це сценарій node.js, який працює на власному сервері. Я телефоную на сторінку node.js безпосередньо з php з file_get_contents (), з іншого php-сервера. Він зараз у повсякденному використанні з 500+ користувачами на день. Можливо, ви заплуталися, тому що "localhost: 3002" шматок? Це тому, що цей приклад працює на моєму локальному комп'ютері з Windows, з двома окремими серверами в iis.
Snorvarg

Я справді розгублений. Це означає, що nodejs.jsнасправді це не вихідний файл, але це URL-адреса, яку ви назвали так, оскільки він містить json? Перший не мав би сенсу, але останній здається мені дуже заплутаним.
Лоренц Мейєр

@Lorenz, я спробував уточнити приклад, змінивши ім'я файлу nodejs js і трохи відредагувавши текст. Щоб відповісти на ваше запитання, файл, перейменований на nodeserver.js, запускається на власному сервері. Виклик http.createServer () створює сервер, який слухає () s для вхідних з'єднань через порт 80.
Snorvarg

Зауважте, що ви можете зателефонувати на сервер node.js безпосередньо з браузера, просто ввівши URL-адресу " localhost: 3002 / nodeserver.js ", і ви отримаєте json-відповідь. File_get_contents () у файлі php витягує вміст з іншого сервера, у цьому випадку сервера node.js.
Снорварг

0

Спробуйте подібне, або ви можете перевірити мій блог на повний зразок коду на nodejs


На вашій сторінці сторінки:

  • Завантажте розетку JS

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

  • Зробіть предмет розетки

var socket = io ();

  • Використовуйте emitфункцію для надсилання даних на сервер вузла.

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

Отже, тепер ваш код буде виглядати так

<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");
    });

  });
});

Тепер на стороні сервера Node зробіть обробник для вашого запиту, щоб отримати ваш запит та надіслати повідомлення всім підключеним пристроям / браузерам (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');
});

Тепер клієнт / браузер / клієнт роблять приймач для отримання повідомлення з сокета з сервера вузлів

<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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.