2

I am trying to get up to speed on proxying websockets. I have some angular code that I modified from a tutorial which tests websocket connections against echo.websocket.org. The code works fine by itself.

<!DOCTYPE html>
<html>
   <meta charset = "utf-8" />
   <title>WebSocket Test</title>

   <script language = "javascript" type = "text/javascript">
      var wsUri = "ws://echo.websocket.org/";
      //var wsUri = "ws://localhost:8015"
      var output;
      var success = 0;
      var failure = 0;

      function init() {

        output = document.getElementById("output");
         output.innerHTML = "";
         testWebSocket();
         writeScore();

      }


      function testWebSocket() {
         websocket = new WebSocket(wsUri);

         websocket.onopen = function(evt) {
            onOpen(evt)
         };

         websocket.onclose = function(evt) {
            onClose(evt)
         };

         websocket.onmessage = function(evt) {
            onMessage(evt)
         };

         websocket.onerror = function(evt) {
            onError(evt)
         };
      }

      function onOpen(evt) {
         writeToScreen("CONNECTED");
         doSend("WebSocket rocks");
         success = success +1;
      }

     function onClose(evt) {
         writeToScreen("DISCONNECTED");
      }

      function onMessage(evt) {
         writeToScreen('<span style = "color: blue;">RESPONSE: ' + 
            evt.data+'</span>'); websocket.close();
      }

      function onError(evt) {
         writeToScreen('<span style = "color: red;">ERROR:</span> '
            + evt.data);
        failure = failure +1;
      } 

      function doSend(message) {
         writeToScreen("SENT: " + message); websocket.send(message);
      }

      function writeToScreen(message) {
         var pre = document.createElement("p"); 
         pre.style.wordWrap = "break-word"; 
         pre.innerHTML = message; 
         output.appendChild(pre);
      }

        function writeScore(){

        var pScore = document.createElement("p");
        pScore.style.wordWrap = "break-word";
        pScore.innerHTML = "Success   "+ success+ "   Failures   "+ failure;
        output.appendChild(pScore);

        }

      window.addEventListener("load", init, false);
   </script>

   <h2>WebSocket Test</h2>
   <div id = "output"></div>

</html>

following the instructions from https://github.com/nodejitsu/node-http-proxy#proxying-websockets

I have tried to set up a simple proxy 2 different ways that will forward the angular page's websocket requests to the same echo.websocket.org connection by altering the wsUri variable in the angular code to point at one of the servers created in this code.

///
// Setup our server to proxy standard HTTP requests
//

var httpProxy = require('http-proxy');
var http = require('http');

var proxy = new httpProxy.createProxyServer({
  target: {
    host: 'echo.websocket.org',
    port: 80
  }
});


var proxyServer = http.createServer(function (req, res) {
  proxy.web(req, res);
});

//
// Listen to the `upgrade` event and proxy the
// WebSocket requests as well.
//
proxyServer.on('upgrade', function (req, socket, head) {
        console.log(socket);
        proxy.ws(req, socket, head);
});


proxyServer.listen(8015);

var test = httpProxy.createServer({
  target: 'ws://echo.websocket.org',
  ws: true
});

test.listen(8014);

Unfortunately the proxied request (for both the sever listening on port 8014 and 8015) triggers the angular websocket.onerror event handler providing me a less than helpful message of 'undefined' for evt.data.

Update:

Chrome displays the following error message in developer tools when I try to open the webpage using the localhost proxies.

index.htm:29 WebSocket connection to 'ws://localhost:8015/' failed: Error during WebSocket handshake: Unexpected response code: 404

Firefox displays the following in it's "Web Console"

Firefox can’t establish a connection to the server at ws://localhost:8015/.

However, the upgrade event is firing as I am seeing the Node's console display the socket information from the console.log() line of the Node JS code. That leads me to believe that the localhost server is being found, begging the question for the origin of the 404 error. I'm not sure if it is related to the finding the proxy (which is having its http upgrade event triggered), or the proxy's target.

How do I get Node JS to proxy the angular websocket connection that works fine when no proxy is between the browser and echo.websocket.org?

2
  • Hi, would you mind to add autoRewrite: true and changeOrigin: true into your createServer()arguments. Commented Jun 1, 2018 at 19:53
  • @gokcand works great now. I have spent days on this. Would you mind putting this into an answer and providing a quick explanation of how adding them changes the proxy behavior since they aren't in the nodejistsu git example? after that I will gladly accept it and award you the bounty. Commented Jun 1, 2018 at 20:06

1 Answer 1

4
+500

TLDR; it is related to setting up the Host: foo.com header before forwarding the proxied request.

Basically, Error during WebSocket handshake: Unexpected response code: 404 means that it actually could not establish any connection with given that wsUri.

As seen from this issue, changeOrigin proposed to be true as default.

However, it is false in our case (by default). So, forwarded request is invalid/malformed without properly setting up the HTTP Host header. You may try to debug this further to see the real HTTP attributes, headers, etc.

Also,

autoRewrite attribute rewrites the location host/port on (201/301/302/307/308) redirects based on requested host/port.

Try to add properties below as createServer() arguments:

autoRewrite: true,
changeOrigin: true,

So, it becomes:

const test = httpProxy.createServer({
  target: 'ws://echo.websocket.org',
  ws: true,
  autoRewrite: true,
  changeOrigin: true,
});

test.listen(8014);

Hope it helps!

Sign up to request clarification or add additional context in comments.

2 Comments

Very helpful that you. I accepted and up-voted the answer. Bounties have a 24 hour wait time before they can be awarded. I will award it to you as soon as I can.
@SemicolonsandDuctTape Thank you :) I'm glad that it helped.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.