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

97

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

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

我没有找到任何完整的答案,大多数时候客户端由 node 服务器运行,因此在我的情况下不适用。因此,我爬遍了所有可能的主题,最终找到了答案;我将尝试分享这一点,并达到明确的目的。

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


这可能对某些人有帮助:https://dev59.com/Dn_aa4cB1Zd3GeqP11YN - user3050478
3个回答

131

首先,我将我的项目放在github上,如果您想访问完整的代码:https://github.com/jdutheil/nodePHP

这是一个非常简单的示例项目:一个Web聊天室。您只需要输入作者和消息,然后按发送按钮即可保存到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。在这里,我们只需要连接到node服务器并等待事件来更新我们的页面。;)

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
好的,当你撰写问题时,有一个选项是“回答自己的问题,分享知识问答风格”,所以我想我们可以像这样分享,如果我错了请原谅 :) - Jérémy Dutheil
4
作为建议,我认为将这个问题的答案 https://dev59.com/C2025IYBdhLWcg3wwYz4 整合到这里是一种更优秀的方法。避免任何Ajax调用,使代码更符合使用Node的方式。现在,PHP可以从数据库中简单地选择信息。 - blackmambo
1
是否可以使用io.connect连接到不同于主应用程序的另一台机器上的节点应用程序,而不是将节点应用程序放在同一服务器上但使用不同端口? - maembe
1
需要使用HMAC签名作为消息认证。这可以确保只有PHP可以向套接字广播消息。套接字将检查已签名的令牌,如果通过,则会广播该消息。这对于防止垃圾邮件和确保数据完整性非常有用。因此,永远不要直接从客户端发布到节点套接字。相反,使用Ajax将其发布到PHP应用程序,然后将其中继到套接字服务器。使用fopen + fwrite或来自PHP的流选择打开与WebSocket服务器的套接字连接相当复杂。 - r3wt
1
同意@Bangash的观点,您可以使用Node.js将数据存储到mysql数据库中,而不是使用PHP,这样会快得多。 - Parthapratim Neog
显示剩余12条评论

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上有两个本地安装,一个是标准的php服务器,而nodejs服务器使用了方便的iisnode包。

“真正”的服务器在Ubuntu上运行。

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


这对我来说毫无意义,因为您正在从php脚本中启动节点服务器。我无法想象任何使用情况。我们需要的是一种在运行的node.js实例和php之间进行通信的方法。 - Lorenz Meyer
不是@Lorenz,那是node.js脚本,在它自己的服务器上运行。我正在使用file_get_contents()从另一个php服务器直接调用node.js页面。现在每天有500多个用户在使用它。也许你会因为“localhost:3002”这一部分而感到困惑?那是因为这个例子在我的本地Windows计算机上运行,有两个独立的iis服务器。 - Tornseglare
我真的很困惑。这意味着 nodejs.js 实际上不是源文件,而是你命名的一个 URL,因为它包含 JSON?前者没有任何意义,但后者对我来说非常令人困惑。 - Lorenz Meyer
喜欢你的解决方案的智能简洁!虽然有点hacky,但对于一个小项目来说非常不错。 - Vaviloff
Botea,你可以在node.js中使用MySQL,没有问题。这个链接可能不完全正确,但会给你一个起点:https://expressjs.com/en/guide/database-integration.html#mysql - Tornseglare
显示剩余5条评论

0

可以尝试类似的方法,或者您可以查看我的博客获取Node.js完整示例代码


在您的页面上:

  • 加载 Socket JS

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

  • 创建socket对象

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

现在客户端/浏览器/客户端端创建一个接收器来接收来自Node服务器的套接字消息

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接