I have a REST api hosted on Amazon EC2, which is written with Nodejs (Express).
In a particular REST call, a reply of about 5MB is sent to the client. Before the client completely receives the reply, client prints following error message.
Premature end of Content-Length delimited message body
I added a connection listener in nodejs server like below to check what is going on the server.
var app = express();
var server = http.createServer(app);
var port = app.get('port');
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
server.on('connection', function (socket) {
log.debug('SOCKET OPENED' + JSON.stringify(socket.address()));
socket.setTimeout(300000); //5 minute timeout
socket.on('end', function () {
log.debug('SOCKET END: other end of the socket sends a FIN packet');
});
socket.on('timeout', function () {
log.warn('SOCKET TIMEOUT');
});
socket.on('error', function (error) {
log.warn('SOCKET ERROR: ' + JSON.stringify(error));
});
socket.on('close', function (had_error) {
log.debug('SOCKET CLOSED. IT WAS ERROR: ' + had_error);
});
});
I observed that SOCKET TIMEOUT gets logged in backend. In above code, I have increased the socket timeout to 5 minutes, but it doesn't seem to have any effect.
Earlier I had the REST API hosted in Google compute engine, and I didn't have this problem back then.
What could be the problem here?
Edit: Here is the code of REST API call.
I have following code in my app.js
require('./routes/index')(app);
Following is the index.js of routes directory.
var changeCase = require('change-case');
var express = require('express');
var routes = require('require-dir')();
module.exports = function (app) {
Object.keys(routes).forEach(function (routeName) {
var router = express.Router();
require('./' + routeName)(router);
app.use('/api/' + changeCase.paramCase(routeName), router);
});
};
As it can be seen, it loops through all the js files in the routes directory and registers the file name as the URL path in app.
Here is the code of this particular route for which I face this problem.
module.exports = function (router) {
router.get("/fetch", function (req, res, next) {
itemModel.fetch(req.user.clientId, function (error, items) {
if (error) {
res.status(500).json({error: error});
} else {
res.json(items); //items is a JSON array
}
});
});
}
Setting timeout for the HTTP server resolved the issue.
var server = http.createServer(app);
var port = app.get('port');
server.listen(port);
server.setTimeout(300000, function (socket) {
});
Related
Tried different methods, but the data is sent to a maximum of one or two clients. How to send data to all the clients connected to the server ? What am I doing wrong?
Server.js:
var PORT = 3000;
var options = {
// 'log level': 0
};
var express = require('express');
var app = express();
var http = require('http');
var server = http.createServer(app);
var io = require('socket.io').listen(server, options);
server.listen(PORT);
app.get('/', function (req, res) {
res.sendfile(__dirname + '/attantions/templates/.default/template.php');
});
io.sockets.on('connection', function (client) {
client.on('attantion', function (data) {
try {
// Tried so
io.sockets.volatile.emit('attantion', data);
// And tried so
io.sockets.emit('attantion', data);
client.emit('attantion', data);
client.broadcast.emit('attantion', data );
} catch (e) {
console.log(e);
client.disconnect();
}
});
});
Client.js:
socket.emit("attantion", data);
socket.on('attantion', function (data) {
pushData(data);
});
See this post for different options for socket.io messages
Send response to all clients except sender (Socket.io)
io.sockets.on('connection', function (client) {
client.on('attantion', function (data) {
//client.emit('attantion', data ); // This will send it to only the client
//client.broadcast.emit('attantion', data); // This will send it to everyone but this client
io.emit('attantion', data); // This will send it to all attached sockets.
});
});
Edit
I wonder if this post can help you?
Socket.io - Cannot load file
I was curious how sending the php file to the client through node.js works? are you using another framework?
Could you show more of what your client code looks like? loading the lib and the instantiation of the socket.
I have a node js ( supported by express js ) http application. So I had a server.js file as follows(not there complete code).
var app = require('./app/app');
var server = http.createServer(app);
server.listen(port, host);
server.on('error', onError);
server.on('listening', onListening);
I later added websocket server to there. So it is like this now.
// app server
var app = require('./app/app');
var server = http.createServer(app);
server.listen(port, host);
server.on('error', onError);
server.on('listening', onListening);
/**
* websocker Server
*/
var WebSocket = require('ws');
var wsServer = http.createServer();
var url = require('url');
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({ server: wsServer });
var express = require('express');
var wsApp = express();
var port = 1337;
wsApp.use(function (req, res) {
res.send({ msg: 'hello' });
});
wss.on('connection', function connection(ws) {
console.log((new Date()) + ' Connection from origin ');
ws.on('message', function incoming(message) {
console.log('received: %s', message);
var json = JSON.stringify({ type:'message', data: {hello : 'hello'} });
ws.send(json);
});
var json = JSON.stringify({ type:'message', data: {hello : 'hello'} });
ws.send(json);
});
wsServer.on('request', wsApp);
wsServer.listen(port, function () { console.log('Ws server Listening on ' + wsServer.address().port); });
Now these two are working happily. What I want is on a POST call to the http server, I want to trigger the web socket server to broadcast something to all clients. My problem is How I can trigger websocket server from http server?
Routes of http server is defined in app.js file. from there how can I call websocker server function?
If you encapsulate your ws functionality in one single javascript file (e.g: websocket.js) you could export your websocket object as a module.
module.exports = wss;
and then require it in your http controller
var wss = require(websocket.js)
In this case it should be easy to use wss.send({...}) wherever you like.
This peace of code is working to me:
//websocket.js
'use strict';
var io = require('socket.io');
var callme;
function Websocket(server) {
var server = io(server);
server.on('connection', function(socket){
console.log('Do something here');
});
callme = function (val) {
//you my choose a specific cliente if you want, read the socket.io doc
server.emit('I may emit it ' + val);
console.log("Called " + val);
return 'Somebody got it';
}
}
Websocket.route = function(req, res, next) {
if(typeof callme == 'function'){
res.send(callme(req.param('t')));
}else{
res.send('Websocket server is not running');
}
};
module.exports = Websocket;
On the express app definition, I put
var Websocket = require('./websocket');
app.use('/blablabla', Websocket.route);
Then, on the server js file, which run the application, I put
var server = http.createServer(app);
var s = new Websocket(server);
This last line works like the tradicional io(server); would work.
After that, when you request the address /blablabla the route will execute your websocket method.
My solution is not in production yet, let me know if somebody got an error.
I am trying to emit message from client side with socket.io ...
Here is my client code:
var socket = io.connect('http://localhost/');
socket.on('connect', function(data){
setStatus('connected');
socket.emit('subscribe', {channel:'update.comment'});
});
Server:
io.sockets.on('connection', function (socket) {
socket.emit('message', { text : 'Welcome!' });
socket.on('subscribe', function (data) {
socket.join(data.channel);
redisClient.subscribe(data.channel);
});
});
Also I get this error message in console:
GET
http://localhost/socket.io?EIO=3&transport=polling&t=1442169984269-1
404 (Not Found)
Full serever:
var app = require('express')();
var http = require('http').Server(app);
var redis = require('ioredis');
var io = require('socket.io')(http);
redisClient = redis.createClient();
//look for connection errors and log
redisClient.on("error", function (err) {
console.log("error event - " + redisClient.host + ":" + redisClient.port + " - " + err);
});
io.sockets.on('connection', function (socket) {
socket.emit('message', { text : 'Welcome!' });
//on subscription request joins specified room
//later messages are broadcasted on the rooms
socket.on('subscribe', function (data) {
socket.join(data.channel);
redisClient.subscribe(data.channel);
});
});
redisClient.on('ready', function(data) {
console.log('#redis ready');
});
redisClient.on("message", function(channel, message){
console.log(channel);
var resp = {'text': message, 'channel':channel};
io.sockets.in(channel).emit('message', resp);
});
http.listen(3000, function(){
console.log('Listening on Port 3000');
});
New Problem Recognized:
Your server is listening on port 3000, but you are attempting to connect on port 80. The error message http://localhost/socket.io?EIO=3&transport=polling&t=1442169984269-1 has no port number on it so that defaults to port 80.
That error message means that your server-side socket.io code is not initialized correctly and thus is not listening for the HTTP request that starts all webSocket connections so when the browser tries to connect on that URL to initiate a socket.io connection, there's nobody on the server-side listening so the web server returns a 404 error back to the browser.
If you are using Express, this is the minimal socket.io initialization to hook it into your server:
var express = require('express');
var app = express();
var server = app.listen(8081);
var io = require('socket.io').listen(server);
For a plain HTTP server, this is the minimal socket.io initialization:
var app = require('http').createServer(handler)
var io = require('socket.io')(app);
app.listen(80);
As always, if you show us the socket.io and web server initialization code you are using, we can help you better with your specific code issue.
I have this basic express app:
var express = require('express');
var app = express();
var PORT = 3000;
var through = require('through');
function write(buf) {
console.log('writing...');
this.queue('okkkk');
}
function end() {
this.queue(null);
}
var str = through(write, end);
/* routes */
app.get('/', function(req, res){
res.send("Hello!");
})
app.post('/stream', function(req, res){
var s = req.pipe(str).pipe(res);
s.on('finish', function() {
console.log('all writes are now complete.'); // printed the first time
});
});
/* listen */
app.listen(PORT, function () {
console.log('listening on port ' + PORT + '...');
});
When I post some data to /stream endpoint for the first time after starting the server I get okkk as the response which is what I expect. However, after that, any requests to /stream endpoint just timeout and not return any response.
Why is it so? What's exactly happening here?
I had this same problem and looks like res was not being finished properly. So I added a callback to my stream and ended que res myself. That fixed my problem:
stream.on('end', () => res.end());
stream.pipe(res);
It worked when I replaced req.pipe(str).pipe(res) with req.pipe(through(write, end)).pipe(res) which essentially makes sure that a new instance of through stream is created for every request.
I've found this script for reading a file an "broadcast" its content to every connection.
var serverServiceConfig={port: 8081};
var express = require("express");
var app = express();
var fs = require('fs');
var socket = require('socket.io');
function readTick(ws){
fs.readFile('tick.json', 'utf8', function (err,data) {
if (!err) {
try {
ws.emit('ticks', data);
} catch (e) {
// handle error
console.log('can not read file');
}
}
});
setTimeout(function () {
readTick(ws);
}, 200);
}
console.log('server is running ...');
app.configure(function(){
app.use(express.static(__dirname + '/'));
});
var server = app.listen(serverServiceConfig.port);
var io = socket.listen(server);
io.sockets.on('connection', function (socket) {
readTick(socket);
socket.on('disconnect', function (socket) {
});
});
The server starts without an error, so far so good. But if i try to connect to the server via ip:port i get the following message:
Cannot GET /
I tested this script on my local machine and it worked (a couple of weeks ago)
From what i "know" or i think is that a route is missing, or?
Any help is more than welcome.
Thank you in advance
Instead of using that function, you should put it in app.get('/', function(){//whatever you want to do//})