how to make socket io | node.js - with SSL working - node.js

i having an issue while using node.js with apache on site.
if using http without SSL node.js with apache are working with my domain at env. file
If I remove the SSL code it runs fine, however with it I get a request to http://mydomain.io/socket.io/1/?t=XXXXXXXXX
but when i enable SSL with let encrypt
my site are working but connect with Node js + socket io having error 404
*Note it's not trying https, which causes it to fail.
I'm testing on chrome, firefox and edge still can't fix.
I apologize if this is a simple question, I'm a node/socket.io newbie.
Thanks!
Here my details code are working when using http | but not working using https with let encrypt domain
const pino = require('pino')
const https = require('https');
const { Boom } = require('#hapi/boom')
const fs = require('fs')
const chalk = require('chalk')
require('dotenv/config')
const express = require('express')
const socket = require("socket.io");
const { toDataURL } = require('qrcode')
const mysql = require('mysql');
require('dotenv').config();
const request = require('request');
const app = express()
const host = process.env.HOST ?? '127.0.0.1'
const port = parseInt(process.env.PORT ?? 3000)
app.use(express.urlencoded({ extended: true }))
app.use(express.json())
const ser = app.listen(port, host, () => {
console.log(`Server is listening on http://${host}:${port}`)
})
const io = socket(ser);
const db = mysql.createConnection({
host: process.env.DB_HOSTNAME,
user: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE
});
db.connect((err) => {
if (err) throw err;
console.log('Mysql Connected...');
});
const sessionMap = new Map()

I've had a similar issue before, you need 2 Different servers, one for http, and one for https.
var usinghttps = false;
if(usinghttps) {
var options = {
key: fs.readFileSync("/etc/letsencrypt/live/us2.swordbattle.io/privkey.pem"),
cert: fs.readFileSync("/etc/letsencrypt/live/us2.swordbattle.io/fullchain.pem"),
};
httpsserver = https.createServer(options, app).listen(443);
}
server = http.createServer(app);
And then to create the socket.io server,
const io = new Server(usinghttps ? httpsserver:server);
This personally worked for me, not sure if it works on all apps.

Related

NodeJs Server: Run two different exported app.js within one http.createServer()

How can I run two app.js within hhtps.createServer() on given condition?
Or you can say two completely different node website within one http.createServer().
Below code is running only html files with on some modification.
Such as folder name with correspond to website folder. For https you can create your certificate, otherwise use http.createServer instead https.createServer.
enter code hereconst path = require("path");
const fs = require('fs');
const http = require('http');
const https = require('https');
const { Server } = require("socket.io");
const static = require('node-static');
const app1 = require('./folder1/app');
const app2 = require('./folder2/app');
let folder1 = new (static.Server)('./folder1');
let folder2 = new (static.Server)('./folder2');
//Some certificate
const options = {
key: fs.readFileSync(path.join(__dirname, './Cert') + '/folder1.com.key', 'utf8'),
cert: fs.readFileSync(path.join(__dirname, './Cert') + '/folder_com.crt', 'utf8')
};
let server = https.createServer(options,(req, res) => {
req.addListener('end', () => {
try {
let hostName = req.headers.host.split(':')[0];
console.log(hostName);
switch(hostName){
case 'folder1.com':
folder1.serve(req, res);
break;
case 'folder2.com':
folder2.serve(req, res)
break;
default:
folder2.serve(req, res)
}
}
catch{
console.log(e);
}
}).resume();
})
const io = new Server(server, {log: false});
let port = process.env.PORT || 443;
server.listen(port);
console.log('Server is listening on port: '+ port);
Are you trying to expose both an http and an https endpoint?
If so, my suggestion would be to only expose https and handle incoming http requests in your webserver such as nginx and have them redirect to https automatically.

Limit of making PUT request

I have a weird problem while I try to make the same PUT request multiple times, it works for about 8,9 times but after I have to refresh the page to work again.
I use React with Node.js (using Sequelize) for request:
React code:
return await axios
.put(`${API_URL}/api/user/createUser`, {
id_game_table: gameTableId,
name: nickName,
})
.then((response) => {
return [response.data, null];
})
.catch((error) => {
return [null, error.response];
});
My Node.js body destructuring:
What my Node.js looks like:
And the requests I was making:
Here, we can see that the first 9 PUT request was a success - this can be seen even in Node.js - but after 9 PUT requests was made all requests that I made was just OPTIONS and no other request was made. As another mention, there is not output in console.
The config for Node.js:
const express = require("express");
const app = express();
const cors = require("cors");
const http = require("http");
const server = http.createServer(app);
const socketIo = require("socket.io");
const index = require("./routes/index");
const port = process.env.PORT || 4001;
app.use(express.json());
app.use(cors());
app.use(index);
app.use("/api/gameTable", require("./routes/gameTable.routes"));
app.use("/api/user", require("./routes/user.routes"));
const io = socketIo(server, { cors: { origin: "*" } });
server.listen(port, () => console.log(`Listening on port ${port}`));
Note: The socket connection doesn't matter, I know that I had this request limit behaviour as well when using Angular with Spring in the past (without socket).

React- can't connect to server socket

I build a server & client.
the client is trying to connect to the server by socket however I'm getting the following error in the console :
Access to XMLHttpRequest at 'http://localhost:5000/socket.io/?EIO=4&transport=polling&t=NS2s-Z_' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
The server:
const express = require('express');
const socketio = require('socket.io');
const http = require('http');
const PORT = process.env.PORT || 5000;
const router = require('./router');
const app = express();
const server = http.createServer(app);
const io = socketio(server);
io.on('connection',(socket) =>{
console.log('[Server] We have new connection !!!');
socket.on('disconnect',()=>{
console.log('[Server] WeUser has left !!!')
});
});
app.use(router);
server.listen(PORT,()=>{
console.log(`[Server] has started listen on port ${PORT}`);
});
The client:
let socket;
const Chat= ({location}) =>{
const ENDPOINT ='localhost:5000';
const [name,setName] = useState('');
const [room,setRoom] = useState('');
useEffect(()=>{
const {name,room} = queryString.parse(location.search) // get url
socket = io(ENDPOINT);
//Update state with new name and room
setName(name);
setRoom(room);
console.log(socket);
// socket.emit('ERROR');
},[ENDPOINT,location.search]);
return (<h1>Chat</h1>);
}
At first, I was sure the problem was that the server isn't on the same port as the client request. But sadly it's not the case.
Edit:
I've changed both ports to be 3000 and it seems to work, however, with any other port it's not. Is there a way the client cant send ack to connection because of os permission
I had the same problem, you can try adding the transport on the client side, worked for me
const socket = io("localhost:5000", { transports: ["websocket"] });
Your express needs to enable CORS. Here is how. Install this package:
npm i cors
require it:
const cors = require('cors');
Then right below your const app = express();, paste this:
app.use(cors());

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.

node.js server and HTTP/2 (2.0) with express.js

Is it possible currently to get node.js HTTP/2 (HTTP 2.0) server? And http 2.0 version of express.js?
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('hello, http2!');
});
var options = {
key: fs.readFileSync('./example/localhost.key'),
cert: fs.readFileSync('./example/localhost.crt')
};
require('http2').createServer(options, app).listen(8080);
EDIT
This code snippet was taken from a conversation on Github.
If you are using express#^5 and http2#^3.3.4, then the correct way to start the server is:
const http2 = require('http2');
const express = require('express');
const app = express();
// app.use('/', ..);
http2
.raw
.createServer(app)
.listen(8000, (err) => {
if (err) {
throw new Error(err);
}
/* eslint-disable no-console */
console.log('Listening on port: ' + argv.port + '.');
/* eslint-enable no-console */
});
Notice the https2.raw. This is required if you want to accept TCP connections.
Note that at the time of this writing (2016 05 06), none of the major browsers support HTTP2 over TCP.
If you want to accept TCP and TLS connections, then you need to start the server using the default createServer method:
const http2 = require('http2');
const express = require('express');
const fs = require('fs');
const app = express();
// app.use('/', ..);
http2
.createServer({
key: fs.readFileSync('./localhost.key'),
cert: fs.readFileSync('./localhost.crt')
}, app)
.listen(8000, (err) => {
if (err) {
throw new Error(err);
}
/* eslint-disable no-console */
console.log('Listening on port: ' + argv.port + '.');
/* eslint-enable no-console */
});
Note that at the time of this writing, I did manage to make express and http2 to work (see https://github.com/molnarg/node-http2/issues/100#issuecomment-217417055). However, I have managed to get http2 (and SPDY) to work using spdy package.
const spdy = require('spdy');
const express = require('express');
const path = require('path');
const fs = require('fs');
const app = express();
app.get('/', (req, res) => {
res.json({foo: 'test'});
});
spdy
.createServer({
key: fs.readFileSync(path.resolve(__dirname, './localhost.key')),
cert: fs.readFileSync(path.resolve(__dirname, './localhost.crt'))
}, app)
.listen(8000, (err) => {
if (err) {
throw new Error(err);
}
/* eslint-disable no-console */
console.log('Listening on port: ' + argv.port + '.');
/* eslint-enable no-console */
});
There is an open pr for express 5.0 since 2018, https://github.com/expressjs/express/pull/3730. Until that is merged, it won't work out of the box.
I have created the solution in the form of a package, https://www.npmjs.com/package/http2-express-bridge
const express = require('express')
const http2Express = require('http2-express-bridge')
const http2 = require('http2')
const { readFileSync } = require('fs')
// Use the wrapper function that returns the application
const app = http2Express(express)
const options = {
key: readFileSync('<Certificate Key>'),
cert: readFileSync('<Certificate file>'),
allowHTTP1: true
};
app.get('/', function (req, res) {
res.send('Hello World')
})
const server = http2.createSecureServer(options, app)
server.listen(3000, () => {
console.log(`listening on port 3000`)
})
This works, and it falls back to Http/1.1 when it receives an Http/1.1 request.
I have also included 'res.push' method for ease of server push. The package works with ESModules and Typescript.
This issue is still around today (2016 as of writing this), so I decided to have a go at making a workaround to make express and http2 packages work nicely together: https://www.npmjs.com/package/express-http2-workaround
Edit: Does not work on any NodeJS version above v8.4 due to the native 'http2' module.
Install via NPM: npm install express-http2-workaround --save
// Require Modules
var fs = require('fs');
var express = require('express');
var http = require('http');
var http2 = require('http2');
// Create Express Application
var app = express();
// Make HTTP2 work with Express (this must be before any other middleware)
require('express-http2-workaround')({ express:express, http2:http2, app:app });
// Setup HTTP/1.x Server
var httpServer = http.Server(app);
httpServer.listen(80,function(){
console.log("Express HTTP/1 server started");
});
// Setup HTTP/2 Server
var httpsOptions = {
'key' : fs.readFileSync(__dirname + '/keys/ssl.key'),
'cert' : fs.readFileSync(__dirname + '/keys/ssl.crt'),
'ca' : fs.readFileSync(__dirname + '/keys/ssl.crt')
};
var http2Server = http2.createServer(httpsOptions,app);
http2Server.listen(443,function(){
console.log("Express HTTP/2 server started");
});
// Serve some content
app.get('/', function(req,res){
res.send('Hello World! Via HTTP '+req.httpVersion);
});
The above code is a working express application that uses both the nodejs http module (for HTTP/1.x) and the http2 module (for HTTP/2).
As mentioned in the readme, this creates new express request and response objects and sets their prototypes to http2's IncomingMessage and ServerResponse objects. By default, it's the inbuilt nodejs http IncomingMessage and ServerResponse objects.
I hope this helps :)

Resources