Node.js + Socket.io + Apache

10

我正在寻找一种将Node.js + Socket.io + Apache集成的方法, 具体为:

  • 我希望Apache继续提供HTML/JS文件。
  • 我希望Node.js在8080端口上监听连接。类似于这样:
var util = require("util"),
    app = require('http').createServer(handler),
    io = require('/socket.io').listen(app),
    fs = require('fs'),
    os = require('os'),
    url = require('url');

app.listen(8080);

function handler (req, res) {

    fs.readFile(__dirname + '/index.html',
  function (err, data) {
    if (err) {
      res.writeHead(500);
      return res.end('Error loading index.html');
    }

    res.writeHead(200);
    res.end(data);
  });
}

io.sockets.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });

  socket.on('my other event', function (data) {
    socket.emit('ok 1', { hello: 'world' });
  });

  socket.on('clientMSG', function (data) {
    socket.emit('ok 2', { hello: 'world' });
  });

});

如果我访问连接到这个服务器的HTML,则可以正常工作,但是我需要前往mydomian.com:8080/index.html。 我想要的是能够前往mydomian.com/index.html,并能够打开套接字连接:

<script>
        var socket = io.connect('http://mydomain.com', {port: 8080});
        socket.on('news', function (data) {
            console.log(data);
            socket.emit('my other event', { my: 'data from the client' });
        });

        socket.on('connect', function (data) {
            console.log("connect");
        });

        socket.on('disconnect', function (data) {
            console.log("disconnect");
        });


            //call this function when a button is clicked
        function sendMSG()
        {
            console.log("sendMSG"); 
            socket.emit('clientMSG', { msg: 'non-scheduled message from client' });
        }

    </script>

在这个例子中,我不得不使用fs.readFile,因为当我访问URL中的端口8080时,它不起作用。

有什么建议吗?谢谢。


如果你只是想提供静态文件,尝试使用nginx而不是apache。Apache为每个请求启动一个新线程,这在某种程度上与使用node的哲学/原因相抵触。 - badunk
3个回答

15

将静态内容从Apache的80端口提供,将动态/数据内容通过Socket.IO服务器在8080端口提供。在Socket.IO应用程序中,您不需要使用app = require('http').createServer(handler)

Apache 80端口 |-------------| 客户端 |------------| Socket.IO 8080端口

var io = require('socket.io').listen(8080);

io.sockets.on('connection', function (socket) {
  io.sockets.emit('this', { will: 'be received by everyone'});

  socket.on('clientMSG', function (from, msg) {
    console.log('I received a private message by ', from, ' saying ', msg);
  });

  socket.on('disconnect', function () {
    sockets.emit('user disconnected');
  });
});

谢谢您的回复。我已经进行了更改,现在看起来客户端似乎没有获取/socket.io/socket.io.js文件。这个文件是由Node中的HTTP服务器提供的吗? - oscarm
1
我已经解决了。将路径更改为/socket.io-client/dist/socket.io.js。谢谢! - oscarm
1
是的,你需要从你的Apache静态服务器上的80端口提供socket.io.js,并在客户端代码中执行类似于<script src=/socket.io.js></script>的操作。 - EhevuTov
1
我不知道这是否有帮助,但如果你在当前目录中使用npm install socket.io安装了它,在:8888运行一个应用程序,你只需要在script标签中添加src="http://mydomain:8888/socket.io/socket.io.js",即使它在node_modules/socket.io/lib/socket.io.js中。 - tester
2
这不会触发“同源策略”违规吗?http://en.wikipedia.org/wiki/Same_origin_policy - stolsvik
是的,它现在触发了。 - user1721713

11

AWS + APACHE + NODEJS + SOCKET.IO + ANGULARJS

服务器端
我在一个生产服务器上运行Apache,使用80端口和NodeJS使用8000端口,这对我有用。根据您的需要更改NodeJS端口...

  1. 在/var/www/html中创建名为“nodejs”的文件夹,用于存放NodeJS服务器的文件
  2. 在除了80端口以外的不同端口上运行Nodejs,例如端口8000
  3. 执行命令:a2enmod proxy_http
  4. 执行命令:a2enmod proxy_wstunnel
  5. 将下面的2行代码添加到/etc/apache2/apache2.conf文件结尾处:

    LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
    LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so 
    
    将接下来的12行代码放在以下文件结尾处:/sites-available/000-default.conf
    (如果你有一个不同的已创建网站,请将这些代码放在那里)

  6. RewriteEngine On
    RewriteCond %{REQUEST_URI}  ^socket.io          [NC]
    RewriteCond %{QUERY_STRING} transport=websocket [NC]
    RewriteRule /{.*}       ws://localhost:8000/$1  [P,L]
    
    RewriteCond %{HTTP:Connection} Upgrade [NC]
    RewriteRule /(.*) ws://localhost:8000/$1 [P,L]
    
    ProxyPass /nodejs http://localhost:8000/
    ProxyPassReverse /nodejs http://localhost:8000/
    
    
    ProxyPass /socket.io http://localhost:8000/socket.io
    ProxyPassReverse /socket.io http://loacalhost:8000/socket.io
    
    ProxyPass /socket.io ws://localhost:8000/socket.io
    ProxyPassReverse /socket.io ws://localhost:8000/socket.io
    
  7. sudo service apache2 restart


客户端
我使用以下 在 AngularJS 中实现 Socket.io,但是我认为这个指南也适用于 socket.io 技术的基本 JavaScript 实现。

调用我的 PHP 服务器:example.com
调用 NodeJS 服务器:example.com/nodejs
调用 NodeJS Socket:example.com <--- 这个调用将由库默认执行

希望可以帮到你!


谢谢,我已经成功解决了在Apache服务器上运行socket.io的问题。 - prateekkathal
使用您的出色答案和其他研究,您可以在此处找到一个完整的示例,其中包括certbot、CORS头和解释(如果没有您的建议,我无法完成它!):https://dev59.com/OGkw5IYBdhLWcg3whK88#62073028 - Dr. Aaron Dishno

0

您可以继续从Apache提供页面,但需要在node.js/socket.io中启用CORS:

index.html(由Apache提供)

<script src = "https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.0/socket.io.js"></script>
<script>
   const socket = io("ws://your.domain.com:8080");
<script>

app.js(在nodejs中):(启用CORS)

const express = require('express');
const app = express();
const http = require('http').Server(app);
const io = require('socket.io')(http, {
    cors: {
      origin: "*",
      methods: ["GET", "POST"]
    }
});

http.listen(8080);

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