I wrote a Web Socket server using socket.io, node-http2 and express in Node.js. The server works as intended, except for the fact that according to Chrome's DevTools socket.io's negotiation requests go through HTTP/1.1 (shown below). The "Protocol" column should be displaying h2 if the request was sent using HTTP/2.
This only happens in Chrome, other browsers use the correct protocol.
The server code (shortened):
var PORT = 8667,
config = require('./config'),
socketioServer = require('socket.io'),
app = express(),
https = require('http2'),
cors = require('cors');
app.use(cors(function(req, callback){
var corsOptions = { origin: false };
if (/^https:\/\/mlpvc-rr\.lc/.test(req.header('Origin')))
corsOptions.origin = true;
callback(null, corsOptions);
}));
app.get('/', function (req, res) {
res.sendStatus(403);
});
var server = https.createServer({
cert: fs.readFileSync(config.SSL_CERT),
key: fs.readFileSync(config.SSL_KEY),
}, app);
server.listen(PORT);
var io = socketioServer.listen(server);
// ...
Browser connection code:
var conn = io('https://ws.'+location.hostname+':8667/', { reconnectionDelay: 5000 });
conn.on('connect', function(){
console.log('[WS] Connected');
});
conn.on('disconnect',function(){
console.log('[WS] Disconnected');
});
Output of testssl.sh:
What do I need to change to make the socket.io requests go through HTTP/2?
A little bit late but with Express4 and Spdy (npm) is working great.
bin/www:
var app = require('../app');
var debug = require('debug')('gg:server');
var spdy = require('spdy');
var fs = require('fs');
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
var options = {
key: fs.readFileSync(__dirname + '/server.key'),
cert: fs.readFileSync(__dirname + '/server.crt')
}
var server = spdy.createServer(options, app);
var io = app.io
io.attach(server);
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
...
app.js:
...
var app = express();
var io = app.io = require('socket.io')();
...
client screenshot:
As discussed in comments Chrome has recently stopped allowing the older NPN negotiation for HTTP/2 and insists on the newer ALPN protocol instead. See this article for more info: https://ma.ttias.be/day-google-chrome-disables-http2-nearly-everyone-may-31st-2016/
So you basically need Node.js to support ALPN which it looks as has only been added in v5 so far: https://github.com/nodejs/node/pull/2564 . An alternative would be to route your NodeJs calls through a webserver which is easier to upgrade OpenSSL (e.g. Nginx or Apache) to support HTTP/2 over ALPN.
You confirmed this was the issue by using the testssl.sh program which confirmed no ALPN support and the fact Firefox uses HTTP/2.
Related
this issue has been boggling my mind for days. There's nothing noticable to me that I have done, but my node port produces an insecure socket, while my site itself is completely secure (ssl). So mathtutortime.com is secure, but this is the error I get when I go to https://www.mathtutortime.com/account/get_tutoring/lobby.php:
I tried reinstalling my ssl certificate, as well as ensuring my ssl certificate isn't expired, but to no avail. I have also gone to the actual part of my site in node having this issue, and it indeed is not secure :( Even though mathtutortime.com IS.
Here's my code for lobby.php:
gather data for site, then create a post request
<script src="https://mathtutortime.com:3001/socket.io/socket.io.js"></script>
<script>
var BACKEND_URL = 'https://mathtutortime.com:3001';
var SESH_END_INCORRECT = 'https://mathtutortime.com/account/get_tutoring/done_incorrect';
var SESH_END_CORRECT = 'https://mathtutortime.com/account/get_tutoring/done_correct';
var name = "<?php echo $_SESSION["username"]?>";
var pass = "<?php echo $_SESSION["password"]?>";
var time = 0;
var role = 'tutor';
$.post(`${BACKEND_URL}/requestWhiteboard`, { name, time, role, pass }, function(res){
window.location.href = `${BACKEND_URL}/whiteboards/${res.whiteboardId}`;
</script>
And here's my server in node:
var fs = require('fs');
var express = require('express');
var bodyParser = require('body-parser');
var all;
var options = {
key: fs.readFileSync('./privatekey.key'),
cert: fs.readFileSync('./certificate.crt'),
requestCert: false,
rejectUnauthorized: false
};
const chat_port = 3001;
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(__dirname + '/public'));
var server = require('https').createServer(options, app);
require('https').globalAgent.options.rejectUnauthorized = false;
var io = require('socket.io').listen(server);
app.post('/requestWhiteboard', function(req, res){
...
}
app.get('/socket.io.js', function(req, res){
res.sendFile(__dirname + '/socket.io.js');
});
var host = '45.79.111.96';
server.listen(chat_port, host, function(){
console.log('listening on *' + chat_port);
});
Also, socket.io.js is in my directory (referenced in an app.get below)
Thanks for any ideas!
When I build my site with ssl on cloudflare my site works clearly
but in nodejs ws server i change with wss server
and read key and pem files on nodejs
I got an error console like this ERR_CERRT_AUTHORITY_INVALID
how can i fix this error? Any idea?
Notes: my wss server port is :8443
I try cloudflare ssl optiond flexible, full and full (stricth)
My app is live chat script coded with nodejs
Here is the code:
var https = require('https');
var fs = require('fs');
var webSocketsServerPort = 8443;
var webSocketServer = require('websocket').server;
var options = { key: fs.readFileSync('key.key'), cert: fs.readFileSync('x.pem') };
var server = https.createServer(options, function (req, res) {
res.writeHead(200);
res.end("deneme\n");
}).listen(webSocketsServerPort);
server.listen(webSocketsServerPort, function () {
console.log((new Date()) + " server geldi " + webSocketsServerPort);
});
var wsServer = new webSocketServer({ httpServer: server });
I have a few questions about configuring socket.io for my node.js application.
When requiring var socket = require('socket.io')( /* HERE */ ), do I need to input the port my server listens where the /* HERE */ is at?
Right below the above line, I have another require function, for a .js file that contains a few constants and a function (see below). When I try to refer to 'socket' in that file it says it's undefined. But since this line is below the require line for the socket.io middleware seen above, why does it say 'undefined'?
const numbers = '1234'
function asd(req,res,next) {
socket.emit('a')
}
module.exports = {
asd
}
For configuring client-side socket.io, I added this line:
var socket = io.connect('https://mydomain')
Do I need to say 'mydomain:port' or is 'mydomain' enough?
This is how you use socket.io
var http = require('http');
var express = require('express');
var path = require('path');
var app = http.createServer();
var io = require('socket.io')(app);
var port = 8081;
io.on('connection', function(socket){
socket.on('event1', function (data) {
console.log(data);
socket.emit('event2', { msg: 'delivered' });
});
});
app.listen(port);
Answer to your second question
Yes, you will need to specify the port you are using
<script src="socket.io.js"></script>
<script>
var socket = new io.Socket();
socket.connect('https://mydomain:8081')
socket.on('your_event',function() {
console.log('your_event receivid from the server');
});
</script>
Here socket will connect to port 8081
This is a simple server side code
var http = require('http');
var io = require('socket.io');
var port = 8081;
// Start the server at port 8081
var server = http.createServer();
server.listen(port);
var socket = io.listen(server);
// example listener
socket.on('event_2', function(client){
console.log('event_2 received');
});
// example emitter
socket.emit('event_1', { hello: 'world' });
I have this node.js server. The problem is sometimes I notice that it gets stuck. That is the client can make requests, but the server doesn't respond, rather it doesn't end the response, it just gets stuck in the server side. If I look in client side dev tools on the http request, it has a gray circle icon meaning waiting for server response. Even if I wait 10 minutes, nothing happens.
The server side also writes things to console on the requests, which doesn't happen when it gets stuck.
On the node.js console, if I then press ctrl+c when it got stuck, I then suddenly see all the console.log messages just appear on the console, and at the same time, the dev tools, recieves all the responses from the server side, i.e. the gray circle changes to green.
Does anyone know what this problem is?
Thanks
var express = require('express');
var https = require("https");
var fse = require("fs-extra");
var bodyParser = require('body-parser');
// INFO
var root = __dirname + '/public';
setUpServer();
// SET UP SERVER
function setUpServer() {
var app = express();
app.use(express.static(root));
app.use(bodyParser.urlencoded({ extended: false }))
app.get('/', function (req, res) {
var dest = 'index.html';
res.sendFile(dest, { root: root + "/pong" });
});
app.post('/get_brain', function (req, res) {
res.end("1");
console.log('Sent master brain to a client!');
});
app.post('/train_and_get_brain', function (req, res) {
res.end("1");
console.log('Sent master brain to a client!');
});
var privateKey = fse.readFileSync('sslcert/key.pem', 'utf8');
var certificate = fse.readFileSync('sslcert/cert.pem', 'utf8');
var credentials = {key: privateKey, cert: certificate};
var httpsServer = https.createServer(credentials, app);
httpsServer.listen(process.env.PORT || 3000, function () {
var host = httpsServer.address().address;
var port = httpsServer.address().port;
console.log('AI started at https://%s:%s', host, port);
});
}
I am reading Professional Node.js and i'm trying to understand connect HTTP middleware framework. I created a simple middleware that returns a function that replies with a custom test string:
function replyText(text) {
return function(req, res) {
res.end(text);
};
}
module.exports = replyText;
But when i try to use this middleware in a connect server. Node gives me an error:
/Users/socomo22/work/hello_world_app_v2.js:8
var app = connect.createServer(replyText('Hello World!'));
^
TypeError: undefined is not a function
But when i simply use:
var app = connect();
app.listen(8080)
It runs without giving any error. I don't understand whether i'm doing any syntatical mistake. How would i use this simple middleware? This is my connect server file:
var connect = require('connect');
// middlewares
var replyText = require('./reply_text');
var app = connect();
var app = connect.createServer(replyText('Hello World!'));
app.listen(8080, function() {
console.log('listening on 8080 port')
});
As pointed by documentation use use API to mount a middleware and a http module to create an instance of server although you can create an instance just with connect as pointed here.
As pointed by #FranciscoPresencia adding .js extension while you require a your local module is optional.
var replyText = require('./reply_text.js');
So your code should look like this and i tested it. Working as intended
var connect = require('connect')
var http = require('http')
var app = connect();
// middlewares
var replyText = require('./reply_text.js');
app.use(replyText('Hello World!'));
http.createServer(app).listen(8080, function() {
console.log('listening on 8080 port')
});
Note: Try to avoid ports like 8080, 80 etc as its a reserved ports that might be used by other apps. This sometimes may cause node to fail.
Adding the output screenshot for your reference
Here You can start server in this way...
var connect = require('connect');
var http = require('http');
var app = connect();
var replyIN = require('./connetFile.js')
app.use(replyIN('Hello there m back again'));
http.createServer(app).listen(8888,function(){console.log('Server has started');});
And this is your connectFile.js
function replyIN(text){
return function (req, res) {
res.end(text);
};
};
module.exports = replyIN;