ExpressJS Routes + Websockets - Share Port - node.js

I have an https expressjs server with websockets (using the 'ws' package). As far as I understand sockets and ports, I should be able to add a route alongside the websocket connections. The main use-case is so that the server can be curled (none of the ws curl requests I've seen online worked.)
Unfortunately I only have 1 port to use for the server and websockets. How can I set this up so that app and server can both listen on the same port?
I've seen a few comments on SO that indicates that it can be done, but no code examples, or it's for very different packages.
I'm using the 'ws' package: https://www.npmjs.com/package/ws
const port = 8888;
const http = require('http');
const https = require('https');
const express = require('express');
const websocket = require('ws');
const app = express();
app.use( express.static('public') );
app.get('/curl', (req, res) => res.send('Hello World')).listen( port );
const httpsServer = https.createServer( credentials, app );
const wss = new websocket.Server({ server: httpsServer });
httpsServer.listen( port, function listening(){
console.log( 'listening on ' + port );
});
Currently I get the "EADDRINUSE" error since I'm using the same port for two 'servers'.
FOLLOW-UP
Express app doesn't need to also listen if another server is.
To curl https, you have to provide the cert details, or use the '-k' (insecure) method.

Your code shows you trying to start two servers on the same port.
This line creates a new http server and attempts to start it on port 8888:
app.get('/curl', (req, res) => res.send('Hello World')).listen( port );
These lines create a new https server and attempt to start it on port 8888 also.
const httpsServer = https.createServer( credentials, app );
httpsServer.listen( port, function listening(){
console.log( 'listening on ' + port );
});
You cannot do that. If you just want one https server that works for both your web requests and your webSocket (a common way to do things), then change your code to this:
const port = 8888;
const https = require('https');
const express = require('express');
const websocket = require('ws');
const app = express();
app.use( express.static('public') );
app.get('/curl', (req, res) => res.send('Hello World'));
const httpsServer = https.createServer( credentials, app );
const wss = new websocket.Server({ server: httpsServer });
httpsServer.listen( port, function listening(){
console.log( 'listening on ' + port );
});
which just removes the .listen(port) that operates on the app object because that will create an http server and start it on the 8888 port.

Related

Certifiction error from chrome browser using ReactJS

i am trying to send an https request from my frontend (reactjs) to backend (nodejs/express).
These two both run in localhost.
Back end server code:
const app = require('./app')
const https = require('https');
const fs = require('fs');
const credentials = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
//connect to the database
require('./db')
const port = 8765;
app.get('/', (req, res) => {
res.send('Now using https..');
});
var server = https.createServer(credentials, app);
//var server = https.createServer(app);
// listen for requests
server.listen(port, () => {
console.log("server starting on port : " + port)
});
front end request:
const {data: Sessions}= await axios.get("https://localhost:8765/...");
i am trying to send an https request from my frontend (reactjs) to backend (nodejs/express).
These two both run in localhost.
Back end server code:
const app = require('./app')
const https = require('https');
const fs = require('fs');
const credentials = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
//connect to the database
require('./db')
const port = 8765;
app.get('/', (req, res) => {
res.send('Now using https..');
});
var server = https.createServer(credentials, app);
//var server = https.createServer(app);
// listen for requests
server.listen(port, () => {
console.log("server starting on port : " + port)
});
front end request:
const {data: Sessions}= await axios.get("https://localhost:8765/...");
doing this request from postman with the exact same parameters produces the desired result.However when i try to do this from frontend i get: GET https://localhost:8765/... net::ERR_CERT_AUTHORITY_INVALID in react chrome extention.I believe this is because i am using a self signed certificate and chrome browser can't verify it's validity.
Is there a way to temporarily disable this verification step from chrome?
If not how else can i solve this?
Not : Doing this with HTTP works fine but i need it to be HTTPS.
If your just going to run it on local host one your machine you can disable the setting at chrome://flags/#allow-insecure-localhost in browser.
This will not fix anything in production tho, only for personal use.

I need to secure my node js website to HTTPS running on the default 80 port of HTTP

I am running my server on ionos hosting and executing nodejs on the default port of 80.
I don't know how to enable the HTTPS for it.
Following is my sample node js server creation code:
const Https = require('https');
const fs = require('fs');
const httpsServer = Https.createServer({
key: fs.readFileSync("private.key"),
cert: fs.readFileSync("Dev-2020-09-12-013930.cer")
}, app);
var io = require('socket.io').listen(Https);
global.SOCKET = io;
const ip = require('ip');
console.log('websocket server start.' + ' ipaddress = ' + ip.address() );
// const socket = io('http://localhost:5000');
httpsServer.listen(80, function () {
console.log('Server port: ' + port);
});
I have generated certificates and added them. On running the server it gives message of server started but does not load on browser.
Try adding these lines of code and see if you get "Hello" text in your browser.
https.get("/", (req, res) => {
res.send("Hello");
});
if that didn't work try doing it this way
httpsServer.get("/", (req, res) => {
res.send("Hello");
});
EDIT
Check out the official documentation https://nodejs.org/api/https.html

Node.JS Express - POST request not working (returning 404) - running in sub-directory on port 8080

I have 2 node.js servers running;
1 on port 8000
another on port 8080
The one on port 8080 will be an API, so need to send POST requests to it.(Endpoint: websocket/test).
When I try to do this, a 404 gets returned.
It is sat in a subdirectory(ROOT/webhook), so not sure if that is the reason, or if its the fact that it is on port 8080?
Socket.io is working fine and connects with no issues, I just cant send a POST request to this server.
Here is the server.js file:
//SOCKET.IO Server
const express = require('express');
const app = express();
const port = 8080;
const fs = require('fs');
const http = require('http');
const https = require('https');
const sslKey = 'HIDDEN';
const sslCert = 'HIDDEN';
const options = {
key: fs.readFileSync(sslKey),
cert: fs.readFileSync(sslCert)
};
const httpServer = http.createServer();
const httpsServer = https.createServer(options);
const io = require('socket.io')(httpsServer);
// FOR HTTP
// httpServer.listen(port, () => {
// console.log("Socket.io http server is listening on port: " + port)
// console.log(__dirname + '/key.pem');
// })
// FOR HTTPS
httpsServer.listen(port, () => {
console.log("Socket.io https server is listening on port: " + port);
})
io.on('connection', function(socket){
console.log('made socket connection', socket.id);
socket.emit('welcome', 'Hiya! Welcome');
app.post('/websocket/test', function() {
console.log('webhook received');
io.emit('webhook', 'You have received a webhook!');
});
});
You almost got everything right. Except you aren't telling your express application to start listening for requests. By just changing this code:
const httpsServer = https.createServer(options);
to this:
const httpsServer = https.createServer(options, app);
Your server should work.

How can I adjust my NodeJs server code to responf to HTTPS requests?

I have a small nodejs server which is working without a problem. Now I am trying to make use of "HTTPS" for security reasons. I have the following code, but when I try to open the page in Firefox via link [http://192.168.2.22:8080/api/users], on the terminal I see DIRECTING >>> https://192.168.2.22:8080/api/users but in the browser, instead of the expected response, I encounter this error:
Secure Connection Failed An error occurred during a connection to
192.168.2.22:8080. SSL received a record that exceeded the maximum permissible length.
Error code: SSL_ERROR_RX_RECORD_TOO_LONG
// Modules /////////////////////////////////////////////////////////////////////
const db = require('./db.js');
// Packages ////////////////////////////////////////////////////////////////////
const colors = require('colors');
const express = require('express');
const app = express();
const fileUpload = require('express-fileupload');
const fs = require('fs');
// Constant Variables //////////////////////////////////////////////////////////
const PORT_SERVER = 8080;
const HOST = '192.168.2.22';
////////////////////////////////////////////////////////////////////////////////
app.use(express.json({limit: '50mb'}));
// app.use(express.urlencoded({limit: '50mb'}));
// set up a route to redirect http to https
app.get('*', function(req, res) {
console.log('DIRECTING >>> https ://' + req.headers.host + req.url);
res.redirect('https://' + req.headers.host + req.url);
});
app.get('/api/users/', async (req, res) => {
console.log('CHECK POINT !!!');
let users = await db.db.get_users();
console.log("USERS : " + users);
res.send(users);
});
// have it listen on 8080
app.listen(PORT_SERVER, () => console.log(`Listen at ${PORT_SERVER}...`));
How can I resolve this? I could not find a solution that I can easily apply to my code, I am kind of a newbie for NodeJs.
Thanks in advance
You have not configured your server for SSL. Configure SSL using the https module like below. In this example, I have created two express one for Http and one for https as we can not run both http and non https on same port.
const express = require('express');
const http = require('http'),
const https = require('https')
const fs = require('fs')
const httpApp = express()
const app = express()
const httpsOptions = {
key: fs.readFileSync("server.key"),
cert: fs.readFileSync("server.crt")
};
httpApp.set('port',80);
httpApp.get("*", function (req, res, next) {
res.redirect("https://" + req.headers.host + "/" + req.path);
});
app.set('port', 443);
app.enable('trust proxy');
http.createServer(httpApp).listen(httpApp.get('port'), function() {
console.log('Express HTTP server listening on port ' + httpApp.get('port'));
});
https.createServer(httpsOptions, app).listen(app.get('port'), function() {
console.log('Express HTTPS server listening on port ' + app.get('port'));
});
The Best way to redirect from non-http to https is to use Nginx web server as a reverse proxy and define redirection rule in Nginx config file.
client--->nginx reverse proxy(with SSL and redirection rules)-->express server
try changing the port to 443, https runs on 443 by default!

express http client connect to server , https client can't connect to server

I've made a server that works with http just fine. The server was up and I was able to connect to it with Chrome and Postman. When I switch the server to https, the server is up, but I can't connect to it with Chrome and Postman. the ssl keys were sign by certbot.
server.js
const https = require('https');
const app = require(__dirname+'/app');
const fs = require('fs');
const port = 80;
const options = {
cert: fs.readFileSync("ssl/v2/fullchain.pem"),
key: fs.readFileSync("ssl/v2/privkey.pem")
}
https.createServer(options, app).listen(port);
console.log(port);
app.js
const express = require('express');
const morgan = require('morgan');
const body_parser = require('body-parser');
const homepage = require(__dirname+'/routes/homepage');
const user = require(__dirname+'/routes/user');
const test = require(__dirname+'/routes/test');
const table = require(__dirname+'/routes/table');
const catalog = require(__dirname+'/routes/catalog');
const cart = require(__dirname+'/routes/cart');
const payment = require(__dirname+'/routes/payment');
const app = express();
app.use(morgan("dev"));
app.use(body_parser.json());
app.use(body_parser.urlencoded({extended: true}));
app.use("/", homepage);
app.use("/user", user);
app.use("/test", test);;
app.use("/table", table);
app.use("/catalog", catalog);
app.use("/cart", cart);
pp.use("/payment", payment);
module.exports = app;
... the server is up, but I can't connect to it with Chrome and Postman
It is not clear from your description how exactly you are trying to connect to the server but I assume that you'll try a simple https://example.com/.
const port = 80;
...
https.createServer(options, app).listen(port);
But based on your code you are trying to use HTTPS on the port reserved for plain HTTP (80) instead of using the default port for HTTPS (443). Thus, https://example.com/ will not work since this will try to use port 443 and you would need to explicitly specify a different port with https://example.com:80/. But the better option would of course to use the default port for HTTPS in the first place in your code, i.e. 443 instead of 80.

Resources