Node.js - 当Nginx反向代理服务时,Websocket拒绝打开连接

时间:2016-03-17 20:22:13

标签: javascript node.js nginx websocket total.js

目前我正在尝试设置一个简单的聊天应用程序。我正在使用total.js框架。我的Node.js程序在[http]://127.0.0.1:8000 /上运行。只要请求URI与加载页面的HTML代码中指定的确切URI匹配,这就有效。例如,转到[http]:// localhost:8000 / wil加载html页面,但是当[http]://127.0.0.1:8000按预期工作时,所有功能都不起作用。

我在尝试将Nginx设置为反向代理时发现了这一点,所以我可以通过转到[http]://127.0.0.1:80 /来达到它。这里会加载html页面,但聊天功能不起作用。

此聊天应用是total.js示例的一部分。

这是创建websocket的index.html文件:

<div class="mb5">
  <button name="open">CONNECT</button>
</div>
<div>
  <button name="close" disabled="disabled">DISCONNECT</button>
</div>
<br />
<div>
  <input type="text" name="message" maxlength="200" style="width:500px" />
  <button name="send" disabled="disabled">SEND</div>
</div>
<br />
<div>
  <textarea id="output" style="width:620px;height:300px" readonly="readonly"></textarea>
</div>
<br />
<div>
  <input type="text" value="" name="username" maxlength="20" style="width:200px" />
  <button name="rename" disabled="disabled">RENAME</div>
</div>

<script type="text/javascript">
  var socket = null;

  $(document).ready(function() {

    $('button').bind('click', function() {

      if (this.name === 'rename') {
        var value = $('input[name="username"]').val();

        if (value.length > 0)
          socket.send(encodeURIComponent(JSON.stringify({
            username: value
          })));

        return;
      }

      if (this.name === 'send') {
        console.log('send');
        send();
        return;
      }

      if (this.name === 'open') {
        connect();
        return;
      }

      console.log('disconnect');
      disconnect();
    });
  });

  function connect() {

    if (socket !== null)
      return;

    $('button[name="open"]').attr('disabled', true);
    $('button[name="close"],button[name="send"],button[name="rename"]').attr('disabled', false);
    socket = new WebSocket('ws://127.0.0.1:8000/');

    socket.onopen = function() {
      console.log('open');
    };

    socket.onmessage = function(e) {
      var el = $('#output');
      var m = JSON.parse(decodeURIComponent(e.data)).message;
      el.val(m + '\n' + el.val());
    };

    socket.onclose = function(e) {
      // e.reason ==> total.js client.close('reason message');
      $('button[name="open"]').attr('disabled', false);
    };
  }

  function send() {
    var el = $('input[name="message"]');
    var msg = el.val();

    if (socket !== null && msg.length > 0)
      socket.send(encodeURIComponent(JSON.stringify({
        message: msg
      })));

    el.val('');
  }

  function disconnect() {

    if (socket === null)
      return;

    $('button[name="close"],button[name="send"],button[name="rename"]').attr('disabled', true);
    $('button[name="open"]').attr('disabled', false);

    socket.close();
    socket = null;
  }
</script>

1 个答案:

答案 0 :(得分:0)

这听起来像同源保护。

除非您的socket.io服务器支持COR并允许来自跨域的访问,否则当从127.0.0.1:8000加载网页时,浏览器将不允许与localhost:8000的连接,反之亦然。您连接的域必须与网页的域匹配,除非您的服务器支持CORS并明确允许跨源连接。

而且,即使localhost:8000127.0.0.1:8000实际上可能是同一台服务器,浏览器也不会允许它。

解决特定问题的常用方法是使用Javascript中的window.location获取当前网页网址中的主机名形式,并使用该主机名构建您的网址,以确保您在页面URL中使用相同的主机名。

例如:

socket = new WebSocket('ws://' + window.location.host + '/');

我认为不言而喻,您的nginx代理也必须专门配置为支持webSocket连接。