I wrote a server application in Node.js.
When I do lsof -p 10893 (10893 is the pid of my Node.js application), I get this:
node 10893 root 19u IPv4 (num) 0t0 TCP ip-X.X.X.X->ip-X-X-X.X:45403 (ESTABLISHED)
node 10893 root 19u IPv4 (num) 0t0 TCP ip-X.X.X.X->ip-X-X-X.X:58416(ESTABLISHED)
This connections are hold and never closed, just when I restart my application.
I have the following code in node.js, which as I understand, should handle this issue:
app.use(function(err, req, res, next) {
res.setTimeout(120000);
res.status(500).send('Unexpected error');
});
But these connection are still appears, even after 120000 ms.
How can I fix it?
Pretty sure this is a Keep-Alive issue. See this question and it's answer for details, but the gist is:
res.set("Connection", "close");
If you want that behavior for all your connections, then add it as a middleware above your routes/router:
app.use(function (req, res, next) {
res.set("Connection", "close");
next();
});
Also, if you want to time out the socket itself, it's a bit trickier:
var http = require('http');
var express = require('express');
var app = express();
var svr = http.createServer(app);
svr.on('connection', function (socket) {
socket.setTimeout(120000, function () {
this.end();
});
});
// other middleware / routes here
app.use(function(err, req, res, next) {
res.status(500).send('Unexpected error');
});
svr.listen(PORT);
EDIT:
Just noticed that your function is an error handler middleware (due to the presence of the err parameter). This means that the timeout would only have been set if there was an error, and not if the request completed successfully.
Related
I have a problem with the socket in my program. export the "io" connection and although I can broadcast from any part of the normal program (just by referring to "io"), I cannot use "socket" and broadcast with it unless it is within the same connection of "io." I would like to know how to use socket from any other part of the program, with functions such as "socket.emit ()" or "socket.broadcast.emit" etc. Or how to call this one.
This is my index.js:
const express = require('express');
const restApi = express();
const cors = require('cors');
const server = require('http').createServer(restApi);
const rutas = require('./src/routes/Routes.js');
const io = require('./src/socket/SocketManager.js');
io.attach(server);
restApi.use(express.json());
restApi.use(express.static('public'));
restApi.use(cors());
restApi.options('*', cors());
server.listen(4040, () => console.log('Listening server in port 4040'));
restApi.all('/*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
restApi.use('/api',rutas);
my managersocket.js:
const io = require('socket.io')();
io.on('connection', function (socket) {
console.log('NUEVA CONEXION: ',socket.id);
socket.emit('recoger',socket.id);
});
module.exports = io;
This is where I would like to use the socket or at least call the function.
and User.js:
var io = require('../../socket/SocketManager');
var RouterUser = function(){
this.practicafuncion = function (req,res){
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
console.log('probando entrar por rest y que salga un mensaje por socket');
res.send({
status:'Aprobado',
msj:'Enviado por rest'
});
//this works correctly. io.sockets.emit('mensaje','**MENSAJESERVIDORPORSOCKET**');
//This is not the problem when using "socket". socket.broadcast.emit('mensaje','**MENSAJESERVIDORPORSOCKET**');
};
}
module.exports = function(){
var instancia = new RouterUser();
return instancia;
};
same is the repository where the whole code is
https://github.com/proxirv/Socket.io-router
socket is a temporary object that exists only for the duration of one particular client connection. And, there can be zillions of them (one or more for each connected client). As such, you don't just export one socket or stuff it in a global and try to use that everywhere.
So, if what you're trying to do is to access the socket.io connection for the user that you just received an http request for, that's a bit more complicated and there are several different ways to approach it.
One approach, I've used before is shown below:
const express = require('express');
const app = express();
const server = app.listen(80);
const io = require('socket.io')(server);
const expsession = require('express-session');
const path = require('path');
// install session middleware
const sessionMiddleware = expsession({
secret: 'random secret',
saveUninitialized: true,
resave: true
});
// run session middleware for regular http connections
app.use(sessionMiddleware);
// run session middleware for socket.io connections
io.use(function(socket, next) {
sessionMiddleware(socket.request, socket.request.res, next);
});
// when a socket.io connection connects, put the socket.id into the session
// so it can be accessed from other http requests from that client
io.on('connection', function(socket) {
// socket.handshake.headers
console.log(`socket.io connected: ${socket.id}`);
// save socket.io socket in the session
console.log("session at socket.io connection:\n", socket.request.session);
socket.request.session.socketio = socket.id;
socket.request.session.save();
});
// any arbitrary express route definition
// Note: you can't send socket.io data in a request that loads an HTML page
// because that client hasn't yet established the socket.io connection
// for that page. The socket.io connections will be created after
// the browser loads this page.
app.get("/", function(req, res) {
const session = req.session;
console.log("\n\npage load\n---------------------------\n");
console.log("session:\n", session);
res.sendFile(path.join(__dirname, "socket-io-session.html"));
});
// Upon an API call from a page that already has a socket.io connection,
// respond to the API call and send something to that page's socket.io socket
app.get("/api/test", function(req, res) {
const session = req.session;
io.sockets.connected[session.socketio].emit('show', "sending some data");
console.log("session:\n", session);
console.log("session.socketio:\n", session.socketio);
res.json({greeting: "hello"});
});
Here are the steps in that concept:
Set up express-session for regular http connections. This gives you a place to store stuff that belongs to one particular client (keyed by a cookie)
Set up express-session for the socket.io connection so you can also have access to express-session data in socket.io connections.
When a socket.io connection happens, store the socket.id in the sesssion. This makes the socket.id available for future http requests from that specific client
When some future http request comes in from that client, you can reach into the session, get the socket.id value (which is just a string) and then use that to get the socket for that user and once you have the socket, you can use socket.emit() to send data just to that user.
If you didn't have other reasons for using express-session, you could also just put the socket.id into a cookie all by itself when the socket.io connection connects and then get the socket.id from the cookie during your http request.
I have tried almost everything, and my mind has now finally given up. Hence, I'm here asking for directions. How on earth can this simple piece of code (let's call it app.js):
var express = require('express');
var app = express();
app.use(function(req, res) {
console.log('Request made')
res.send('Hello World!');
});
app.listen(3000, function() {
console.log('Example app listening on port 3000!');
});
When run like node app.js result in the following outcome in my terminal, considering the fact that I've only hit localhost:3000 once:
Example app listening on port 3000!
Request made
Request made
Request made
Request made
Request made
Request made
Request made
...continues...
For some reason I end up with "Request made" being repeated again and again although the request is done and delivered to the browser.
The same is true if I use app.get('*', function(req, res) { ... }) instead of app.use(function(req, res) { ... }).
If I turn to something more specific, like app.get('/', function(req, res) { ... }) the repetition stops and I get one "Request made" as expected. However, I need to match all incoming requests - in my app I'm doing something way more complicated than logging "Request made" :)
Any ideas? Thanks!
Node: 8.11.2
Express: 4.16.3
You need to do something and then pass the results to next callback instead of sending a response which makes it recursive since it's intercepting a response and then doing the same causing a loop.
// this middleware will not allow the request to go beyond it
app.use(function(req, res, next) {
res.send('Hello World');
});
// requests will never reach this route
app.get('/', function (req, res) {
res.send('Welcome');
});
You need to call next() to invoke middleware
app.get('/', function (req, res, next) {
try {
// do something and return result
res.send('Welcome');
} catch(e) {
next(e)
}
});
app.use(function (err, req, res, next) {
console.log('Error occurred')
res.status(err.statusCode).send(err.message);
});
I am trying to send data to the server with the Ajax POST function, and then receive it at the server side with Node.js (and then manipulate it there) but the only problem is that I am unable to find any function at the Node.js side to allow me,accomplish this.I would really like it if you guys could help me out on how to do this as even related threads, I visited on many websites were not very helpful.
Thanks
It will be much easier for you to use some Node-framework like express, to handle all that routes and requests.
You can install it and body-parser module with these commands:
npm install express --save
npm install body-parser --save
Visit express API References to find out more: http://expressjs.com/4x/api.html
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
// Handle GET request to '/save'
app.get('/save', function(req, res, next){
res.send('Some page with the form.');
});
// Handle POST request to '/save'
app.post('/save', function(req, res, next) {
console.log(req.body);
res.json({'status' : 'ok'});
});
app.listen(3000);
Inside your app.post() route you can get access to any post data using req.body. So your S_POST["name"] will be req.body.name in this case.
here's a simple example:
var http = require('http');
http.createServer(function (request, response) {
switch(request.url){
case '/formhandler':
if(request.method == 'POST'){
request.on('data', function(chunk){
console.log('Received a chunk of data:');
console.log(chunk.tostring());
});
request.on('end', function(){
response.writeHead(200, "OK", {'Content-Type' : 'text/html'});
response.end()
});
}
break;
}
}
Also see this page.
I have an ExpressJs (version 4.X) server, and I need to correctly stop the server.
As some requests can take on long time (1-2 seconds), I must reject new connections and wait the end of all the requests in progress. Kill the server in the middle of some tasks could put the server in an unstable state.
I've tried the following code:
//Start
var app = express();
var server = https.createServer(options, app);
server.listen(3000);
//Stop
process.on('SIGINT', function() {
server.close();
});
However, this code doesn't close keep-alive connections, and some clients can keep the connexion for a long time.
So, how can I properly close all connections ?
You could use some middleware to block new requests if the server is being shut down.
var app = express(),
shuttingDown = false;
app.use(function(req, res, next) {
if(shuttingDown) {
return;
}
next();
});
var server = https.createServer(options, app);
server.listen(3000);
process.on('SIGINT', function() {
shuttingDown = true;
server.close(function(){
process.exit();
});
});
Is it possible to wrap every request coming through express.js in a domain or trycatch see trycatch info here?
I am trying to create a 'catch all' of sorts (the express error handler middleware does not catch async calls) to be sure any errors I miss are handled with a 500 being sent to the user.
If you have an asynchronous function call (eg. process.nextTick()), then it will be outside the scope of express' error handler, thus killing the process entirely. Thus, using the express error handler will not work in all cases.
Express already has error handler implementation. It inherit it from connect. To use it you need to add it as the last middleware point (last app.use(...) call). For example:
var express = require('express')
, app = express();
app.use(app.router);
app.use(express.errorHandler());
// app.get(...), app.post(...), app.listen(...), etc.
If you want to handle all errors with simple 500 response code, you could replace express.errorHandler() with you own function. In that case your code will looks like:
var express = require('express')
, app = express();
app.use(app.router);
app.use(function(err, req, res, next){
if (!err) return next();
res.send(500);
});
// app.get(...), app.post(...), app.listen(...), etc.
More information about that way could be found in express error example comments in code
UPDATE:
Of course you could use domain for each request. You could wrap each request separately or use wrapping for router to handle ALL exceptions. Code is following:
var express = require('express')
, http = require('http')
, app = express()
, domain = require('domain');
//app.use(app.router);
app.use(function(req, res, next){
var d = domain.create();
d.on('error', function(er) {
console.log('error, but oh well', er.message);
res.send(500);
});
// explicitly add req and res
d.add(req);
d.add(res);
d.run(function() {
app.router(req, res, next);
});
});
app.get('/', function(req,res){
process.nextTick(function(){
throw new Error('Check Error');
});
});
http.createServer(app).listen(3000, function(){
console.log('Express server listening on port 3000');
});
!!BUT!! never use this in production. The reason of that is in nature how JS throw work. It will definitely be a cause of leaking in your application and make it even more unstable. You could use such error handling to implement custom algorithm of shutdown (for example to close already opened connection). More information about right use of domain could be found in documentation.
To monitor the leaking you could use the technique from this article.
UPDATE 2:
I just can't leave this not finished. trycatch code:
var express = require('express')
, http = require('http')
, app = express()
, domain = require('domain')
, trycatch = require('trycatch');
//app.use(app.router);
app.use(function(req, res, next){
trycatch(function(){
app.router(req, res, next);
}, function(er){
console.log(er.message);
res.send(500);
});
});
app.get('/', function(req,res){
process.nextTick(function(){
throw new Error('Check Error');
});
});
http.createServer(app).listen(3000, function(){
console.log('Express server listening on port 3000');
});
I had review the source of trycatch and there was no any magic. It still be cause of leaks. trycatch has domain under the hood.