Как интегрировать 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
Что ж, когда вы пишете вопрос, есть опция «ответить на свой вопрос, поделиться знаниями в стиле вопросов и ответов», поэтому я подумал, что мы можем поделиться таким образом, извините, если я ошибаюсь :)
Джереми Дютейл
4
В качестве предложения я думаю, что включение ответа на этот вопрос здесь stackoverflow.com/questions/5818312/mysql-with-node-js является превосходным методом. избегая любого вызова ajax и делая код более встроенным с использованием node. Теперь PHP может просто выбирать информацию из базы данных.
blackmambo 05
1
Можно ли подключиться к приложению узла с помощью io.connect, если оно находится на другом компьютере, чем ваше основное приложение, вместо того, чтобы приложение узла находилось на том же сервере, но с использованием другого порта?
maembe
1
требует подписи hmac в качестве аутентификации сообщения. это гарантирует, что только php может транслировать сообщения в сокет. сокет проверит подписанный токен, и, если он пройдет, ti передаст сообщение. это хорошо для предотвращения спама и обеспечения целостности данных. поэтому никогда не отправляйте сообщения напрямую в сокет узла от клиента. вместо этого отправьте сообщение в приложение php с помощью ajax, а затем передайте его на сервер сокетов. Довольно нетривиально открыть соединение сокета с сервером websocket с помощью fopen + fwrite или выбора потока из php.
r3wt
1
Согласовано с @Bangash, вы можете использовать Node.js для хранения данных в базе данных mysql вместо PHP, что сделает его
намного
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-server работает с аккуратным пакетом iisnode .

«Настоящий» сервер работает на ubuntu.

Я думаю, что это изящное и простое решение для связи между двумя серверами, но, может быть, у кого-то есть комментарии по этому поводу?

Snorvarg
источник
Для меня это не имеет смысла, потому что вы запускаете сервер узлов из сценария php. Я не могу представить себе какой-либо вариант использования для этого. Что нам нужно, так это способ связи между запущенным экземпляром node.js и php.
Лоренц Мейер
Нет @Lorenz, это скрипт node.js, работающий на собственном сервере. Я вызываю страницу node.js прямо с php с помощью file_get_contents (), с другого php-сервера. Сейчас им ежедневно пользуются более 500 пользователей. Может быть, вы запутались, потому что кусок "localhost: 3002"? Это потому, что этот пример работает на моем локальном компьютере под управлением Windows с двумя автономными серверами в iis.
Snorvarg 05
Я действительно смущен. Это означает, что nodejs.jsна самом деле это не исходный файл, а URL-адрес, который вы так назвали, потому что он содержит json? Первое не имеет никакого смысла, но второе мне кажется очень запутанным.
Лоренц Мейер
@Lorenz, я попытался прояснить пример, изменив имя файла js файла nodejs и немного отредактировав текст. Чтобы ответить на ваш вопрос, файл, теперь переименованный в nodeserver.js, запускается на собственном сервере. Вызов http.createServer () создает сервер, который прослушивает () s для входящих подключений на порту 80.
Snorvarg 08
Обратите внимание, что вы можете вызвать сервер node.js прямо из браузера, просто введя URL-адрес « localhost: 3002 / nodeserver.js », и вы получите json-ответ. File_get_contents () в файле php получает контент с другого сервера, в данном случае с сервера node.js.
Snorvarg 08
0

Попробуйте сделать то же самое, или вы можете проверить мой блог, чтобы получить полный образец кода на nodejs


На вашей странице:

  • Загрузить сокет JS

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

  • Сделайте объект из розетки

var socket = io ();

  • Используйте emitфункцию для отправки данных на сервер узлов.

socket.emit ('новое_уведомление', {
сообщение: 'сообщение',
заголовок: 'заголовок',
значок: 'значок',
});

Итак, теперь ваш код будет выглядеть так

<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;
}
Викуджангид
источник