3

I have some Javascript in a Chrome Extension that runs every 3 seconds and attempts to make a connection to a local WebSocket Server.

setInterval(attemptConnection, 3000);

function attemptConnection() {

try {
    var exampleSocket = new WebSocket("ws://localhost:8080");
    exampleSocket.onmessage = function (event) {
        var JsonObject = JSON.parse(event.data);
        document.getElementById(JsonObject.elementTagValue).setAttribute("value", JsonObject.valueToSet);

    }
}

catch(err) {
//do something here
    }

I only expect to be running a local WebSocket server at certain points in time. If a connection is made, the WebSocket Server will send some JSON data that the javascript will use immediately.

When I go into the developer tools, I see that I am getting ERR_CONNECTION_REFUSED in the console many times because there is obviously nothing at that end-point and that is expected behavior. Is there a way to suppress those console outputs or handle this issue better?

EDIT - Updated the code and I still get errors output to the console

setInterval(attemptConnection, 3000);

function attemptConnection() {
    var exampleSocket = new WebSocket("ws://localhost:8080");
    exampleSocket.onmessage = function (event) {
        var JsonObject = JSON.parse(event.data);
        document.getElementById(JsonObject.elementTagValue).setAttribute("value", JsonObject.valueToSet);
        exampleSocket.send(event.data);

        exampleSocket.onerror = function () {
            //do nothing
        }
    }
}
alexanderbird
  • 3,847
  • 1
  • 26
  • 35
Jason Bayldon
  • 1,296
  • 6
  • 24
  • 41
  • Maybe if you use `exampleSocket.onerror`? – Barmar May 04 '17 at 20:51
  • `try/catch` doesn't work because the error happens asynchronously. – Barmar May 04 '17 at 20:53
  • Network errors always are logged to console, regardless whether they're handled in JS or not. You can hide them through the devtools settings, though – Bergi May 04 '17 at 21:35
  • Is there a risk of flooding the console with a ton of errors? I hope I am not going to bring Chrome crashing down if I left the browser open for a long time. – Jason Bayldon May 04 '17 at 21:40
  • Half-baked idea: is there a way to check if the connection will succeed before calling `new WebSocket('...')`? I haven't looked into it. – alexanderbird May 04 '17 at 22:00

3 Answers3

1

Assumed that you have to handle errors with onerror you should handle the onclose as well. The simplest check is the error code 1000 that means a normal socket close

exampleSocket.onclose = (event) => {
   if (event.code != 1000) {
      // "Normal closure, meaning that the purpose for which the connection was established has been fulfilled.";
   }
}

While a complete handling of error codes is described here, and I'm putting here for your convenience:

     exampleSocket.onclose = (event) => {
        if (event.code == 1000)
            reason = "Normal closure, meaning that the purpose for which the connection was established has been fulfilled.";
        else if(event.code == 1001)
            reason = "An endpoint is \"going away\", such as a server going down or a browser having navigated away from a page.";
        else if(event.code == 1002)
            reason = "An endpoint is terminating the connection due to a protocol error";
        else if(event.code == 1003)
            reason = "An endpoint is terminating the connection because it has received a type of data it cannot accept (e.g., an endpoint that understands only text data MAY send this if it receives a binary message).";
        else if(event.code == 1004)
            reason = "Reserved. The specific meaning might be defined in the future.";
        else if(event.code == 1005)
            reason = "No status code was actually present.";
        else if(event.code == 1006)
           reason = "The connection was closed abnormally, e.g., without sending or receiving a Close control frame";
        else if(event.code == 1007)
            reason = "An endpoint is terminating the connection because it has received data within a message that was not consistent with the type of the message (e.g., non-UTF-8 [http://tools.ietf.org/html/rfc3629] data within a text message).";
        else if(event.code == 1008)
            reason = "An endpoint is terminating the connection because it has received a message that \"violates its policy\". This reason is given either if there is no other sutible reason, or if there is a need to hide specific details about the policy.";
        else if(event.code == 1009)
           reason = "An endpoint is terminating the connection because it has received a message that is too big for it to process.";
        else if(event.code == 1010) // Note that this status code is not used by the server, because it can fail the WebSocket handshake instead.
            reason = "An endpoint (client) is terminating the connection because it has expected the server to negotiate one or more extension, but the server didn't return them in the response message of the WebSocket handshake. <br /> Specifically, the extensions that are needed are: " + event.reason;
        else if(event.code == 1011)
            reason = "A server is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request.";
        else if(event.code == 1015)
            reason = "The connection was closed due to a failure to perform a TLS handshake (e.g., the server certificate can't be verified).";
        else
            reason = "Unknown reason";
     }

var exampleSocket = new WebSocket("ws://localhost:8080");
    exampleSocket.onmessage = function (event) {
        var JsonObject = JSON.parse(event.data);
        console.log(JsonObject)
        exampleSocket.send(event.data);

        exampleSocket.onerror = function () {
            //do nothing
        }
    }
exampleSocket.onclose = (event) => {
            if (event.code == 1000)
                reason = "Normal closure, meaning that the purpose for which the connection was established has been fulfilled.";
            else if(event.code == 1001)
                reason = "An endpoint is \"going away\", such as a server going down or a browser having navigated away from a page.";
            else if(event.code == 1002)
                reason = "An endpoint is terminating the connection due to a protocol error";
            else if(event.code == 1003)
                reason = "An endpoint is terminating the connection because it has received a type of data it cannot accept (e.g., an endpoint that understands only text data MAY send this if it receives a binary message).";
            else if(event.code == 1004)
                reason = "Reserved. The specific meaning might be defined in the future.";
            else if(event.code == 1005)
                reason = "No status code was actually present.";
            else if(event.code == 1006)
               reason = "The connection was closed abnormally, e.g., without sending or receiving a Close control frame";
            else if(event.code == 1007)
                reason = "An endpoint is terminating the connection because it has received data within a message that was not consistent with the type of the message (e.g., non-UTF-8 [http://tools.ietf.org/html/rfc3629] data within a text message).";
            else if(event.code == 1008)
                reason = "An endpoint is terminating the connection because it has received a message that \"violates its policy\". This reason is given either if there is no other sutible reason, or if there is a need to hide specific details about the policy.";
            else if(event.code == 1009)
               reason = "An endpoint is terminating the connection because it has received a message that is too big for it to process.";
            else if(event.code == 1010) // Note that this status code is not used by the server, because it can fail the WebSocket handshake instead.
                reason = "An endpoint (client) is terminating the connection because it has expected the server to negotiate one or more extension, but the server didn't return them in the response message of the WebSocket handshake. <br /> Specifically, the extensions that are needed are: " + event.reason;
            else if(event.code == 1011)
                reason = "A server is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request.";
            else if(event.code == 1015)
                reason = "The connection was closed due to a failure to perform a TLS handshake (e.g., the server certificate can't be verified).";
            else
                reason = "Unknown reason";
                console.error(reason);
         }

I have added here a full WebSocket client wrapper that handles reconnect as well by means of autoReconnectInterval and maxAttempts through a simple reconnect logic (porting from WebSocket node official examples).

function WebSocketClient() {
  this.number = 0; // Message number
  this.autoReconnectInterval = 5 * 1000; // ms
  this.maxAttempts = 3;
  this.attempts = 0;
}
WebSocketClient.prototype.open = function(url) {
  var self = this;
  this.url = url;

  this.instance = new WebSocket(this.url);
  this.instance.onopen = () => {
    self.onopen();
  }
  this.instance.onmessage = (data, flags) => {
    self.number++;
    self.onmessage(data, flags, this.number);
  }
  this.instance.onclose = (e) => {
    switch (e) {
      case 1000: // CLOSE_NORMAL
        console.log("WebSocket: closed normally");
        break;
      default: // Abnormal closure
        if (self.attempts < self.maxAttempts) self.reconnect(e);
        self.attempts++;
        break;
    }
    this.onclose(e);
  }
  this.instance.onerror = (e) => {
    switch (e.code) {
      case 'ECONNREFUSED':
        self.reconnect(e);
        break;
      default:
        self.onerror(e);
        break;
    }
  }
}
WebSocketClient.prototype.send = function(data, option) {
  try {
    this.instance.send(data, option);
  } catch (e) {
    this.instance.emit('error', e);
  }
}
WebSocketClient.prototype.reconnect = function(e) {
  var self = this;

  console.log("WebSocketClient: retry in %s ms attempt %d", self.autoReconnectInterval, self.attempts);
  setTimeout(function() {
    console.log("WebSocketClient: reconnecting...");
    self.open(self.url);
  }, self.autoReconnectInterval);
}
WebSocketClient.prototype.onopen = function(e) {
  console.log("WebSocketClient: open", arguments);
}
WebSocketClient.prototype.onmessage = function(data, flags, number) {
  console.log("WebSocketClient: message", data);
}
WebSocketClient.prototype.onerror = function(e) {
  console.log("WebSocketClient: error");
}
WebSocketClient.prototype.onclose = function(e) {
  console.log("WebSocketClient: closed");
}

var wsc = new WebSocketClient();
wsc.open('wss://localhost:8080/');
wsc.onopen = function(e) {
  console.log("WebSocketClient connected:", e);
  this.send("echo");
}
wsc.onmessage = function(data, flags, number) {
  console.log("WebSocketClient message", data);
}
Community
  • 1
  • 1
loretoparisi
  • 15,724
  • 11
  • 102
  • 146
  • Thanks. I I tried that but I still am outputting errors to the console. I dont think the socket is ever opened, the error is occuring while the connection is being attempted. – Jason Bayldon May 04 '17 at 21:10
  • I have added a code snippet, run it in your client and tell me which is the error code. – loretoparisi May 04 '17 at 21:11
  • Console outputs "The connection was closed abnormally, e.g., without sending or receiving a Close control frame" and "ERR_CONNECTION_REFUSED" – Jason Bayldon May 04 '17 at 21:14
  • Ok so it is error code `1006`. This means that the Control frame (Close, Ping or Pong) has not been sent. Is your WebSocket client code all in the above snippet? The WebSocker server is sending this special code for a abnormal client execution. – loretoparisi May 04 '17 at 21:20
  • I have included all the client javascript code for the Chrome extension. The Web Socket server runs local on the client (it is just a way to pass values to Chrome - another process triggers the server to start). However, the server is not running when I am getting that error, so I assume that error 1006 is generated regardless of whether a connection is made or not. – Jason Bayldon May 04 '17 at 21:27
  • @JasonBayldon Ok, so you need a retry logic and error code detection, please check out my last snippet then! – loretoparisi May 04 '17 at 21:46
  • Thanks. However, I am still outputting a bunch of 'WebSocket connection to 'wss://localhost:8080/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED' errors. – Jason Bayldon May 04 '17 at 21:54
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/143448/discussion-between-loretoparisi-and-jason-bayldon). – loretoparisi May 04 '17 at 21:58
  • 1
    Accepting your answer since it is the most comprehensive for others. – Jason Bayldon May 09 '17 at 13:01
0

You can't use try/catch to catch this error because it happens asynchronously. You should use an onerror event handler.

function attemptConnection() {
    var exampleSocket = new WebSocket("ws://localhost:8080");
    exampleSocket.onmessage = function (event) {
        var JsonObject = JSON.parse(event.data);
        document.getElementById(JsonObject.elementTagValue).setAttribute("value", JsonObject.valueToSet);

    };
    exampleSocket.onerror = function() {
        // do nothing
    };
}
Barmar
  • 741,623
  • 53
  • 500
  • 612
0

You may be able to only log 1 error if you clear the timeout in your error handler. You can also start another Timeout in your onmessage function so it will only run when it is getting messages. Give it a try

var timer = null;

function attemptConnection() {
    var exampleSocket = new WebSocket("ws://localhost:8080");

        exampleSocket.onmessage = function (event) {
        timer = setTimeout(attemptConnection, 100);
        var JsonObject = JSON.parse(event.data);
        document.getElementById(JsonObject.elementTagValue).setAttribute("value", JsonObject.valueToSet);
        exampleSocket.send(event.data);
    }
    exampleSocket.onerror = function (event) {
          console.log('error')
            //do nothin
          clearTimeout(timer)

      }
}

attemptConnection();
mrsq
  • 235
  • 2
  • 14
  • The issue is that while browsing I don't know when the socket server is going to be available so I poll it continuously. – Jason Bayldon May 04 '17 at 21:48