Как интегрировать 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.

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


Для меня это не имеет смысла, потому что вы запускаете сервер узлов из сценария 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;
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.