如何集成nodeJS + Socket.IO和PHP?


98

我最近一直在寻找,以找到一种在nodeJS和PHP之间进行通信的好方法。这里是一个想法:nodeJS还是一个相当新的东西,仅使用它开发一个完整的应用程序可能有点棘手。而且,您可能只需要项目的一个模块(例如实时通知,聊天等),而您想使用PHP来管理所有其他内容,因为它对您来说可能更容易(而且您可以利用现有框架,例如CodeIgniter或Symfony)。

我想有一个简单的解决方案; 我不想使用cURL或第三方服务器在Apache和Node服务器之间进行通信。我想要的是能够在客户端的简单Javascript中捕获来自节点的事件。

我没有找到完整的答案,大多数情况下客户端都是由节点服务器运行的,因此不适用于我的情况。因此,我检索了所有可能的主题,最后找到了答案;我将尽力分享这一点,并提出一个明确的观点。

希望这可以帮助一些人!;)

Answers:


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

连接新用户时,我们注册了事件回调;每次我们收到一条消息(代表一个聊天消息)时,我们都会将其广播给所有连接的用户。现在,棘手的部分:客户端!这个部分大部分时间都花在了我身上,因为我不知道在没有nodeServer的情况下可以运行Socket.IO代码的脚本(因为客户端页面将由Apache提供)。

但是一切都已经完成;当您使用npm安装Socket.IO模块时,脚本可用/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
那么,当你写一个问题,有一个选项“回答你自己的问题,分享知识问答式”的,所以我想我们可以分享这样的,对不起,如果我错了:)
杰里米Dutheil先生

4
作为建议,我认为在此处合并此问题的答案stackoverflow.com/questions/5818312/mysql-with-node-js是一种更好的方法。避免任何ajax调用,并使代码与node的使用更加内联。现在,PHP可以简单地从数据库中选择信息。
blackmambo

1
如果节点应用程序与主应用程序位于不同的计算机上,而不是节点应用程序位于同一服务器上但使用不同的端口,则可以使用io.connect连接到该节点应用程序吗?
maembe

1
需要hmac签名作为消息身份验证。这样可以确保只有php才能将消息广播到套接字。套接字将检查已签名的令牌,如果令牌通过,则ti将广播该消息。这对于防止垃圾邮件和确保数据完整性很有帮助。因此永远不要直接从客户端发布到节点套接字。而是使用ajax发布到php应用,然后将其中继到套接字服务器。用fopen + fwrite或从php中选择流来打开到websocket服务器的套接字连接是很简单的。
r3wt 2015年

1
同意@Bangash,您可以使用Node.js将数据存储到mysql数据库中,而不是使用PHP,这将使数据存储速度更快
Parthapratim Neog,2016年

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中的简单代码,借助file_get_contents()调用node-js服务器:

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

效果很好,当我加载php页面时,它依次调用nodeserver.js页面,该页面对knall对象进行了json处理。

我在Windows 10的iis上运行了两个localhost安装,一个标准的php-server,而nodejs-server与整齐的iisnode软件包一起工作。

“真实”服务器在ubuntu上运行。

我认为这是用于两台服务器之间通信的简洁易用的解决方案,但也许有人对此有何评论?


这对我来说毫无意义,因为您是从php脚本中启动节点服务器。我无法想象任何用例。我们需要的是一种在正在运行的node.js实例与php之间进行通信的方法。
洛伦兹·梅耶

没有@Lorenz,它是在自己的服务器上运行的node.js脚本。我直接从另一个PHP服务器的file_get_contents()从php调用node.js-page。现在,每天有500多个用户在使用它。也许您因为“ localhost:3002”这部分而感到困惑?这是因为此示例在我的本地Windows计算机上运行,​​在iis中有两个独立服务器。
Snorvarg

我真的很困惑 这意味着它nodejs.js实际上不是源文件,而是您这样命名的URL,因为它包含json?前者没有任何意义,但后者在我看来非常混乱。
洛伦兹·迈尔

@Lorenz,我试图通过更改nodejs js文件的文件名来澄清示例,并稍微编辑文本。为了回答您的问题,现在已重命名为nodeserver.js的文件在其自己的服务器上运行。所述http.createServer()调用在端口80将创建一个服务器,它听()■传入的连接
Snorvarg

请注意,您可以直接从浏览器中调用node.js服务器,只需输入url“ localhost:3002 / nodeserver.js ”,您将得到一个json响应。php文件中的file_get_contents()从另一台服务器(在本例中为node.js服务器)获取内容。
Snorvarg

0

尝试类似的方法,或者您可以在我的博客上查看关于nodejs的完整示例代码


在页面上:

  • 加载套接字JS

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

  • 使对象成为套接字

var socket = io();

  • 使用该emit功能将数据发送到nodeserver。

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

  });
});

现在,在节点服务器端,为您的请求创建处理程序,以获取请求并将消息发送到所有连接的设备/浏览器(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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.