1

So I wrote a Node.js WebSocket server and tested it on my computer. I ran the server by typing node server.js in my command line, and in my Node.js I include:

const websocketServer = new WebSocket.Server({
    port: 8080
});

To create the WebSocket server. I then wrote a JavaScript (and HTML and CSS) client that connects to that WebSocket server, I ran that client using Adobe Brackets IDE, and established a WebSocket connection to my WebSocket server running on my localhost by saying let websocket = new WebSocket("ws://localhost:8080");

Everything worked perfectly. I worked on both the client and WebSocket server for days and days with no issues at all.

Now, my client and WebSocket server are finished, and I want to deploy my WebSocket server onto Heroku so that other users can connect to it and use it using my client. My client is uploaded onto a separate webserver where users can access it.

So, I deployed my WebSocket server onto Heroku and I deployed my client onto my separate server. In my client I changed the line let websocket = new WebSocket("ws://localhost:8080"); to let websocket = new WebSocket("ws://cryptic-bayou-05102.herokuapp.com"); (cryptic-bayou-05102 is the automatically generated name given to my WebSocket server by Heroku)

However, now when I load my client in my browser, I get an error saying

WebSocket connection to 'ws://cryptic-bayou-05102.herokuapp.com/' failed: Error during WebSocket handshake: Unexpected response code: 307

I believe that the issue is in my WebSocket server, where I have the code:

const websocketServer = new WebSocket.Server({
    port: 8080
});

I assume that this code will not work on Heroku since Heroku probably doesn't work the same as a regular server, and so there's no such thing as "port:8080" and requests coming in are directed elsewhere. From what I've found online, I need to somehow configure my WebSocket server to dynamically adjust the port that it listens on according to what Heroku assigns it.

So... My question is, how do I do that? What do I need to change to allow my WebSocket server and client to establish a WebSocket connection?

Thanks in advance! Any answer is a huge help.

Update: I've continued to look into this for the last couple hours. I can't seem to find anybody else getting a 307 error. I've found many 400/500 errors, but nobody seems to be seeing a 307 error... I tried one solution that I found online which is to use +process.env.PORT as the port to run the server on, so I tried it out and it didn't change a thing. I logged out the value of +process.env.PORT and using heroku logs, it gave me Listening on port: 18201 which is perfect, and exactly what I want.... However I am still getting the same error.

On top of this, I went back and read through the code of an older Node.js server+client project of mine from a while back (also hosted on Heroku) and the code there is exactly the same as my code here... I'm doing the exact same things which have worked for me before with no error, except now I can't get them to work without giving me an error... It's quite frustrating.

Edit again: I just wanted to add (for clarification) that I'm getting no server-side errors at all, and my server logs every 5 seconds that it's still running and that everything is still working. It's only the client that has an error. (Also, the server never seems to acknowledge that there was a request to connect, it's like the server never even receives the request sent from the client.)

Another update: Okay... So I thought that the issue might be that I am attempting to establish a ws connection without creating a http server to upgrade from, so I changed the code in my WebSocket server from:

const WebSocket = require("ws");
const webSocketServerPort = +process.env.PORT || 80;

const websocketServer = new WebSocket.Server({
    port: webSocketServerPort
});

to:

const WebSocket = require("ws");
const http = require("http");
const webSocketServerPort = +process.env.PORT || 80;

const httpServer = http.createServer();

httpServer.listen(webSocketServerPort,function(){
    console.log("Server is listening on port " + webSocketServerPort);
});

const websocketServer = new WebSocket.Server({
    server: httpServer
});

When I tested that code on my localhost, everything worked perfectly again, and it was like nothing changed (that's good!), but then when I deployed it to Heroku and tried again... The error is still there... What am I doing wrong? If this doesn't fix it, what will? I've been trying for so many hours now to get this to work, and nothing that I've tried has made even a tiny difference...

And yet another update: Previously I've been only passing in the url of my project when initializing a ws connection, like so let websocket = new WebSocket("ws://cryptic-bayou-05102.herokuapp.com"); and I would get a 307 error in my browser. I did that because every time I boot up the server it listens on a different port, and I thought that Heroku would dynamically re-route me... But when that clearly didn't work, I tried specifying the port after the server booted up, and explicitly connecting to the proper port, like this let websocket = new WebSocket("ws://cryptic-bayou-05102.herokuapp.com:29598");...

And that didn't fix it either! But what it did do is that it made the 307 error go away??? It no longer prints out any errors (the dev console is entirely blank), but there's no connection established and the server never even knows that somebody is trying to connect....... This makes no sense to me. Why would it stop the error from appearing, and yet not have any effect on anything else at all? What in the world is going on? (After about one minute of doing nothing it eventually says that the connection timed out...)

When I try printing out the 307 error to the dev console, I see the following: image of 307 error in dev console

Ders
  • 1,068
  • 13
  • 16
OOPS Studio
  • 732
  • 1
  • 8
  • 25
  • 1
    Questions like this don't usually gain much traction. I would try updating it from 'what is my bug' to 'how do I debug'. You might also want to shorten it to include only relevant details. – Ders Feb 17 '21 at 06:04
  • @Ders Thanks for the tip. You're right, as I troubleshot more and gained more info, I realized that it's getting very long and confusing. I'll probably leave it overnight and see if anybody can help me, but if nobody answers then I'll re-write it tomorrow morning to be more concise, provide more crucial information with fewer words, and better describe the problems and wanted solution. We'll see how it goes... – OOPS Studio Feb 17 '21 at 06:16
  • 1
    It looks like [setting the port to the port Heroku decides to proxy to](https://stackoverflow.com/questions/28706180/setting-the-port-for-node-js-server-on-heroku), with a fallback for development, is mandatory. You do not need the unary + operator, as that just attempts to cast Heroku's provided environment variable, which you can trust. You might try to [catch the 307](https://stackoverflow.com/questions/25779831/how-to-catch-websocket-connection-to-ws-xxxnn-failed-connection-closed-be) and examine it using `console.log`. I am not very experienced with ws. – Ders Feb 17 '21 at 06:17
  • @Ders Thank you very much for the response. I have tried setting the port to the port Heroku decides to proxy to (I actually read that exact SO post earlier today!) and that didn't work... Also ty for letting me know, I wasn't sure what the + was for, but now I know that I can remove it (and I will). I tried catching the 307 error and printing it out. It turns out that it's a massive object with tons of properties (some set myself), but nothing particularly useful that I can see. (And way too much information to post here for others to view.) It seems like that may be a dead end... – OOPS Studio Feb 17 '21 at 06:30
  • Although I think it was a great idea to try and I appreciate you suggesting it! – OOPS Studio Feb 17 '21 at 06:31
  • @Ders Okay, I posted a screenshot of the Event object (the 307 error) into my question, but it's mostly collapsed, and only expanded to the second degree. I'm 99% sure that it won't be helpful, but since the post is already so long I figure there's no harm in including it and seeing if anybody can make sense of it or if it will help anything. – OOPS Studio Feb 17 '21 at 06:34
  • 1
    It looks like you `console.log`ed an _Event_ object. I am not familiar with catching WebSocket errors, but I would hope there is a way. – Ders Feb 17 '21 at 07:07
  • Yes! It's an event object. I believe that event object _is_ the error though. (It contains the word "error" in several places). I received that event object by running the following code: `websocket.onerror = function(err){console.log(err);};` – OOPS Studio Feb 17 '21 at 08:33
  • I could be wrong tho. – OOPS Studio Feb 17 '21 at 08:33
  • 1
    Try looking at the [useful error properties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#examples). To make sure this isn't a client issue please try using your frontend connection method to connect to the [echo server wss://echo.websocket.org](https://www.websocket.org/echo.html). – Ders Feb 17 '21 at 16:51
  • 1
    Are you sure your server is not seeing the request and happily sending the Temporary Redirect? I would try to look at the [access logs] to see whether the request to upgrade to a WS connection is hitting the server (making it through the Heroku layer). If the requests are reaching your server, to debug I would push server code up that is basically an echo WS server until you get it working right. If they are making it through then you have configuration / Heroku issues. – Ders Feb 17 '21 at 16:52
  • @Ders Okay, I will try those things! It may be my server sending the 307 error, although I've ran this server on other hosts and it never has any error (I've tested it more than 300 times without receiving a single error, ever.) and it's only Heroku that is giving me this error... But at the same time, I've got a similar server working on Heroku before without issue... So it's kind of a weird place to be. I'll try printing the access logs first, and if I see a request reach the server then I'll try to get a simple echo connection established. Thanks for the tip! – OOPS Studio Feb 17 '21 at 21:36
  • (I'll probably end up having to reconfigure my Heroku app anyway. Which would be alright too.) – OOPS Studio Feb 17 '21 at 21:36

1 Answers1

2

Okay I figured it out... Apparently Heroku was silently blocking my requests because they were ws requests. I changed to a wss request and it worked perfectly on the first try. I have no idea why it's that way, but I'm glad that it works.

Apparently Heroku gives a 307 error when you attempt to upgrade from https to ws? I'm not sure why it wouldn't tell me something closer to "Can't change from secure connection to insecure ws connection" but I guess that's what they want... ?

However, that seems very weird to me given that I've made another app in Heroku and successfully upgraded from https to ws without any error at all... I still have no idea why it silently failed every time I tried when it had never done that before, but whatever. I'm happy to have it working finally. (Although it's sad that all this trouble was caused by me literally missing off a single "s" in my request, and Heroku couldn't even clue me in...)

Thank you very very very much for the help @Ders. I really appreciate your time and your help meant a lot to me.

OOPS Studio
  • 732
  • 1
  • 8
  • 25