Express and WebSocket listening on the same port
Based on your code and comments, here's a super simple example of how it would work together.
First, the http-server.js
- a typical express app, except that we do not start the server with app.listen()
:
'use strict';
let fs = require('fs');
let express = require('express');
let app = express();
let bodyParser = require('body-parser');
app.use(bodyParser.json());
// Let's create the regular HTTP request and response
app.get('/', function(req, res) {
console.log('Get index');
fs.createReadStream('./index.html')
.pipe(res);
});
app.post('/', function(req, res) {
let message = req.body.message;
console.log('Regular POST message: ', message);
return res.json({
answer: 42
});
});
module.exports = app;
Now, the ws-server.js
example, where we create the WSS server from a node native http.createServer()
. Now, note that this is where we import the app, and give this native http.createServer the app instance to use.
Start the app with PORT=8080 node ws-server.js
:
(Note you're launching the second, socket related, file (ws-server) not the first, http related, file (http-server).)
'use strict';
let WSServer = require('ws').Server;
let server = require('http').createServer();
let app = require('./http-server');
// Create web socket server on top of a regular http server
let wss = new WSServer({
server: server
});
// Also mount the app here
server.on('request', app);
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log(`received: ${message}`);
ws.send(JSON.stringify({
answer: 42
}));
});
});
server.listen(process.env.PORT, function() {
console.log(`http/ws server listening on ${process.env.PORT}`);
});
Finally, this sample index.html
will work by creating both a POST and a Socket "request" and display the response:
<html>
<head>
<title>WS example</title>
</head>
<body>
<h2>Socket message response: </h2>
<pre id="response"></pre>
<hr/>
<h2>POST message response: </h2>
<pre id="post-response"></pre>
<script>
// Extremely simplified here, no error handling or anything
document.body.onload = function() {
'use strict';
// First the socket requesta
function socketExample() {
console.log('Creating socket');
let socket = new WebSocket('ws://localhost:8080/');
socket.onopen = function() {
console.log('Socket open.');
socket.send(JSON.stringify({message: 'What is the meaning of life, the universe and everything?'}));
console.log('Message sent.')
};
socket.onmessage = function(message) {
console.log('Socket server message', message);
let data = JSON.parse(message.data);
document.getElementById('response').innerHTML = JSON.stringify(data, null, 2);
};
}
// Now the simple POST demo
function postExample() {
console.log('Creating regular POST message');
fetch('/', {
method: 'post',
headers: {
"Content-type": "application/json"
},
body: JSON.stringify({message: 'What is the meaning of post-life, the universe and everything?'})
})
.then(response => response.json())
.then(function (data) {
console.log('POST response:', data);
document.getElementById('post-response').innerHTML = JSON.stringify(data, null, 2);
})
.catch(function (error) {
console.log('Request failed', error);
});
}
// Call them both;
socketExample();
postExample();
}
</script>
</body>
</html>
Note you'll need a quite recent browser, one that has both WebSocket and fetch APIs for this client side part, but it's irrelevant anyway, it just gives you the gist of it.
http and ws on the same port 80, "Amazing Zlatko Method™."
You'll have a file, say main.js, with
var app = express()
and many lines of express code.
It is perfectly OK to have as much middleware as you want in the usual way with no changes.
var app = express()
app.use(session(session_options))
app.use(passport.initialize())
app.use(passport.session())
app.use('/static', express.static('static'))
// etc etc
app.get ...
app.get ...
app.post ...
app.post ...
Normally at the end of that file you would
app.listen(80, (err) => { ... })
Delete that.
//app.listen(80, (err) => { ... })
No other changes in the express app file.
In your websocket file, say multiplayer.js, you would normally have
const WebSocket = require('ws');
const wss = new WebSocket.Server({
port: 9999,
perMessageDeflate: false
})
In fact, change to
const WebSocket = require('ws');
/*const wss = new WebSocket.Server({
port: 2828,
perMessageDeflate: false
});*/
let WSServer = WebSocket.Server;
let server = require('http').createServer();
let app = require('./main'); // note, that's your main.js file above
let wss = new WSServer({
server: server,
perMessageDeflate: false
})
server.on('request', app);
TBC, note that, surprisingly to me, WebSocket.Server does indeed naturally want to listen on 80.
And at the end of that file
server.listen(80, function() {
console.log(`Amazing Zlatko Method™ combo server on 80`);
});
Note! - launch the 'multiplayer.js' file (not 'main.js').
It works perfectly. Amazing stuff.