从 Nginx 到 express.js 上的 socket.io 的反向代理上的“无法获取”

Posted

技术标签:

【中文标题】从 Nginx 到 express.js 上的 socket.io 的反向代理上的“无法获取”【英文标题】:"Cannot GET" on reverse proxy from Nginx to socket.io on express.js 【发布时间】:2015-10-06 01:20:50 【问题描述】:

我已经关注this tutorial,让 Node.js 通过私有网络在两台 Ubuntu 14.04 服务器上通过 nginx 工作(Node.js 在 myappserver 上 - 可通过私有 IP myprivatewebserver 访问并通过 mypublicappserver 公开访问 - 以及 mywebserver 上的 Nginx) .到目前为止一切正常 - 我可以通过 Nginx 访问 myprivateappserver:3000 上的 node.js 应用程序,方法是转到 http://mywebserver/node。

但是,当我尝试在 express.js 上的 socket.io 中运行 chat application 时,当我直接访问它时它可以工作 (http://mypublicappserver:3000) 但是,当我尝试通过我的 Nginx 代理访问它时 (@ 987654325@),我在浏览器和萤火虫控制台中得到“Cannot GET /node” “网络错误:404 未找到 - http://mywebserver/node”。

如果我从 mywebserver curl http://myprivateappserver:3000,我可以从我的 socket.io 应用程序中获取 index.html

我的 /etc/nginx/sites-available/default 包含:

location /node
proxy_pass http://myprivateappserver:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;

我的 index.js 是:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

app.get('/', function(req, res)
  res.sendFile(__dirname + '/index.html');
);

io.on('connection', function(socket)
  console.log('a user connected');
  socket.on('disconnect', function()
    console.log('user disconnected');
  );
  socket.on('chat message', function(msg)
    io.emit('chat message', msg);
  );
);

http.listen(3000, function()
  console.log('listening on *:3000');
);

而我的 index.html 是:

<!doctype html>
<html>
  <head>
    <title>Socket.IO chat</title>
    <style>
      *  margin: 0; padding: 0; box-sizing: border-box; 
      body  font: 13px Helvetica, Arial; 
      form  background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; 
      form input  border: 0; padding: 10px; width: 90%; margin-right: .5%; 
      form button  width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; 
      #messages  list-style-type: none; margin: 0; padding: 0; 
      #messages li  padding: 5px 10px; 
      #messages li:nth-child(odd)  background: #eee; 
    </style>
  </head>
  <body>
    <ul id="messages"></ul>
    <form action="">
      <input id="m" autocomplete="off" /><button>Send</button>
    </form>
    <script src="/socket.io/socket.io.js"></script>
    <script src="http://code.jquery.com/jquery-1.11.1.js"></script>
    <script>
      var socket = io();
      $('form').submit(function()
        socket.emit('chat message', $('#m').val());
        $('#m').val('');
        return false;
      );
      socket.on('chat message', function(msg)
        $('#messages').append($('<li>').text(msg));
      );
    </script>
  </body>
</html>

这是我第一次涉足 nginx/node/express/socket(我通常是 Apache/Cakephp 人员),所以我很可能遗漏了一些非常简单的东西,但也非常感谢任何关于如何调试的指针出错了

【问题讨论】:

【参考方案1】:

我认为这样会更好:

location /node
proxy_pass http://myprivateappserver:3000/; # add "/"
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;

proxy_pass加'/',然后app.get('/')也ok!

【讨论】:

【参考方案2】:

location ~ /(node|socket.io)  
.......


这也适用于没有“^”和“\”符号的情况。

【讨论】:

【参考方案3】:

好奇的好回答。我想补充一点,如果您使用 sub_filter,则不必调整 node.js 应用程序。你的 nginx 一定是用那个模块编译的。

location ~ ^/(node|socket\.io) 
    #your proxy directives
    sub_filter /node /;

【讨论】:

【参考方案4】:

这是因为 SocketIO 默认使用/socket.io 路径,所以你需要配置 Nginx 使其不仅代理/node 请求,还代理/socket.io

location ~ ^/(node|socket\.io) 
    #your proxy directives

(顺便说一句,你好像有错别字:你写了proxypass,但正确的形式是proxy_pass。其他proxy指令也是如此)

您还需要在 NodeJS 服务器文件中再执行一次编辑。替换:

app.get('/', function(req, res)

与:

app.get('/node', function(req, res)

现在应该可以了。

这不是唯一的解决方案。您也可以通过对 Nginx 配置进行一些更改来更改 SocketIO path,但上面描述的解决方案对我来说似乎是最简单的。祝你好运!

【讨论】:

非常感谢@Curious。这将花费我很长时间来为自己解决 - 我不明白代理地址与它所代理的应用程序是如何相互关联的。当我粘贴它们时,我重新插入了从 proxy_pass 等指令中删除的下划线,以免混淆到达此页面的其他人。再次感谢。 @theotherdy 不客气)代理时如何转换 URL 有多种选择,您可以阅读更多 here。下划线怎么样 - 你做了一件好事,但你错过了$httpupgrade 变量中的下划线。祝你好运:) 我想我需要做一些 Nginx 手册阅读。很好地发现了那个缺失的下划线 - 现在也添加了那个。再次感谢 万一其他人关注这个线程,我早上大部分时间都在意识到,当我的 CakePHP 应用程序由 mywebserver 提供服务时,我尝试设置一个连接: var socket = io('mywebserver/node');这被正确代理并连接到mypublicappserver:3000 但是,虽然连接在那里,但 Socket.io 认为我是说我希望通信在“节点”命名空间中,所以发出不起作用!但是更改为: var nsp=io.of('/node') 然后 nsp.on('connection', function(socket)etc. 它可以工作! 请帮助我。我不想让请求传递给我的应用程序。 ***.com/questions/39574238/…

以上是关于从 Nginx 到 express.js 上的 socket.io 的反向代理上的“无法获取”的主要内容,如果未能解决你的问题,请参考以下文章

Express.js 中删除 req.body 时的空对象

无法将多部分表单数据从 React 正确发送到 Express Js

计时器运行时,Express.js上的504 Gateway Timeout错误

没有 Express.js 的 node.js 上的 Access-Control-Allow-Origin

Express.JS 服务器连接到远程网络上的主机

express.js 网站图标未显示