Is there a way to close a response? I can use res.end() but it doesn't actually close the socket.
What I want to achieve: I am writing a Java program which interfaces with the network, and I am writing a NodeJS server for this. Java code:
String line;
while((line = in.readLine()) != null) {
System.out.println("RES: "+line);
}
But this just keeps hanging. No end connection, still waiting for input from the socket.
Node:
exports.getAll = function (req, res) {
res.set("Content-Type", "text/plain");
res.set(200);
res.send(..data..);
res.end();
}
however res.end() does not close the connection. As said before, Java keeps thinking there will be something next so it is stuck in the while loop.
Solved by setting a HTTP header to close the connection instead of default keep-alive strategy.
res.set("Connection", "close");
In case someone who really wants just to close the connection finds this, you can use res.socket or res.connection to get the net.Socket object which comes with a destroy method:
res.connection.destroy();
Related
This example is taken from the documentation, but it only does echo.
const listener = Deno.listen({ port: 8080});
console.log("listening on 0.0.0.0:8080");
for await (const conn of listener) {
Deno.copy(conn, conn).finally(() => conn.close());
}
Adding this line await conn.write(new TextEncoder().encode('Test')) inside the for, i get to send data from the server to the client but only when the connection is made.
What I want to achieve is to be able to send information at any time, from the server to the client, but I have no idea how to achieve it, I don't get much information on the subject and my head is exploding.
From already thank you very much!
I have a project where I have a iOS Objective-C app trying to talk to a Node.js server. I'm using socket.io (iOS) and socket.io on node.js.
The problem I am trying to solve is to get a message from the device to the server, and have the server return a response. To this end I'm attempting to do it via sending a message and expecting an acknowledgement containing the data the device is after.
The device code looks like this:
void (^serverAck)(uint64_t, void (^)(NSArray *)) = [_socket emitWithAck:#"ListProjects" withItems:#[]];
serverAck(0, ^(NSArray* data) {
if ([data count] == 0) {
NSError *error = [NSError errorWithDomain:#"CRXServer" code:1 userInfo:nil];
failureBlock(error);
} else {
successBlock(data);
}
});
And the node.js code looks like this:
var SocketIO = require('socket.io');
var io = SocketIO(8099);
io.on('connection', function(socket) {
socket.on('ListProjects', function(data, getProjectsCallback) {
database.allProjects(function getAllProjectsCallback(err, rows) {
getProjectsCallback(rows);
});
});
});
When I attempt to run this, getProjectsCallback crashes the server because it is not a function. From comments made on another thread, I understand that this will be a function if the call to the server is correct and expecting an ack.
Anyone know what I've done wrong?
P.S. Her's a dump from socket.o's log showing the request coming in:
engine:socket packet +0ms
socket.io-parser decoded 20["getProjects"] as {"type":2,"nsp":"/","id":0,"data":["getProjects"]} +14ms
socket.io:socket got packet {"type":2,"nsp":"/","id":0,"data":["getProjects"]} +15ms
socket.io:socket emitting event ["getProjects"] +0ms
socket.io:socket attaching ack callback to event +0ms
Getting all projects ...
Releasing connection
Got the project list
/Users/derekclarkson/projects/crux-Server/node_modules/mysql/lib/protocol/Parser.js:82
throw err;
^
TypeError: getProjectsCallback is not a function
at getAllProjectsCallback (/Users/derekclarkson/projects/crux-Server/Server.js:20:13)
at Query.executeCodeblockCallback [as _callback] (/Users/derekclarkson/projects/crux-Server/Database.js:321:17)
So it looks like socket.io is attaching an ack, but somehow it's not being passed to the callback.
Not sure if it's a bug or a protocol limitation, but it doesn't work when you pass an empty array to emitWithAck:withItems:. You'll see that server-side, data contains your callback function, rather than getProjectsCallback as you expect.
So, two options:
in that situation, recognise that the first argument to your listener handler will be the callback, rather than the second
or add any random data to the items array (e.g. #[#"x"])
I think I would go for the second option in case someone fixes this issue in the future.
Is it possible using Node.js and express to drop a request for certain route? I.E. not return a http status or any headers? I'd like to just close the connection.
app.get('/drop', function(req, res) {
//how to drop the request here
});
To close a connection without returning anything, you can either end() or destroy() the underlying socket.
app.get('/drop', function(req, res) {
req.socket.end();
});
I don't think there's any way to drop the connection at your end but keep the client waiting until it times out (i.e. without sending a FIN). You'd perhaps have to interact with your firewall in some way.
Yes you can.
All you need to do is call the res.end method optionally passing in the status code.
Use one of the following methods:
res.end();
res.status(404).end();
If you wanted to also set the headers, then you'd use the res.set method.
See below
res.set('Content-Type', 'text/plain');
res.set({
'Content-Type': 'text/plain',
'Content-Length': '123',
'ETag': '12345'
})
For details have a look here
http://expressjs.com/api.html
You could do this wherever you want to close the connection:
res.end()
Update: I posted this code here, after I added all (to 99%) possibilities one by one, and it still gave me a 120sec timeout...buffled.
So, ok, I figured it takes exactly 120sec (ok, 122sec) on my Windows 7 machine, until the FIN handshake is started. I want to do it immediately. HTTP RFC793 says
FIN: No more data from sender
Looks to me I do not send any data anymore. I tried all this bloated code, still a Hello World server...
var http = require('http')
var server = http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'})
res.write('HELLO WORLD!\n')
res.end()
res.setTimeout(0)
req.abort() // 1) TypeError: Object #<IncomingMessage> has no method 'abort'
req.on('socket', function (socket) {
socket.setTimeout(0)
socket.on('timeout', function() {
req.abort()
})
})
})
server.timeout = 0
server.setTimeout(0)
server.listen(1337, '192.168.0.101')
So how to do 1) ? (Actually sends a RST like this...)
And how to do the whole thing HTTP conform?
Of course in the end I will be lucky to use nodejs as in websocket stuff and all this, but if conversion on my website means a thing of two minutes, and I have a million concurrent users (huh?), sending a FIN immediately could mean I have two million concurrent users (do the math). ;) Ok, to be on the sure side: Sending a FIN means the socket is closed?
Ah, eah, ok, since you are on, how do I console.log(res) or console.log(req)? It gives me [object Object]. (Update: I tried console.log(res.toSource()), gives me a TypeError?
Edit: Found the answer here.
If you want to close the connection, send a connection: close header. If you do this, then it will not leave the connection open for reuse.
Looking at the example given at the nodejs domain doc page: http://nodejs.org/api/domain.html, the recommended way to restart a worker using cluster is to call first disconnect in the worker part, and listen to the disconnect event in the master part. However, if you just copy/paste the example given, you will notice that the disconnect() call does not shutdown the current worker:
What happens here is:
try {
var killtimer = setTimeout(function() {
process.exit(1);
}, 30000);
killtimer.unref();
server.close();
cluster.worker.disconnect();
res.statusCode = 500;
res.setHeader('content-type', 'text/plain');
res.end('Oops, there was a problem!\n');
} catch (er2) {
console.error('Error sending 500!', er2.stack);
}
I do a get request at /error
A timer is started: in 30s the process will be killed if not already
The http server is shut down
The worker is disconnected (but still alive)
The 500 page is displayed
I do a second get request at error (before 30s)
New timer started
Server is already closed => throw an error
The error is catched in the "catch" block and no result is sent back to the client, so on the client side, the page is waiting without any message.
In my opinion, it would be better to just kill the worker, and listen to the 'exit' event on the master part to fork again. This way, the 500 error is always sent during an error:
try {
var killtimer = setTimeout(function() {
process.exit(1);
}, 30000);
killtimer.unref();
server.close();
res.statusCode = 500;
res.setHeader('content-type', 'text/plain');
res.end('Oops, there was a problem!\n');
cluster.worker.kill();
} catch (er2) {
console.error('Error sending 500!', er2);
}
I'm not sure about the down side effects using kill instead of disconnect, but it seems disconnect is waiting the server to close, however it seems this is not working (at least not like it should)
I just would like some feedbacks about this. There could be a good reason this example is written this way that I've missed.
Thanks
EDIT:
I've just checked with curl, and it works well.
However I was previously testing with Chrome, and it seems that after sending back the 500 response, chrome does a second request BEFORE the server actually ends to close.
In this case, the server is closing and not closed (which means the worker is also disconnecting without being disconnected), causing the second request to be handled by the same worker as before so:
It prevents the server to finish to close
The second server.close(); line being evaluated, it triggers an exception because the server is not closed.
All following requests will trigger the same exception until the killtimer callback is called.
I figured it out, actually when the server is closing and receives a request at the same time, it stops its closing process.
So he still accepts connection, but cannot be closed anymore.
Even without cluster, this simple example illustrates this:
var PORT = 8080;
var domain = require('domain');
var server = require('http').createServer(function(req, res) {
var d = domain.create();
d.on('error', function(er) {
try {
var killtimer = setTimeout(function() {
process.exit(1);
}, 30000);
killtimer.unref();
console.log('Trying to close the server');
server.close(function() {
console.log('server is closed!');
});
console.log('The server should not now accepts new requests, it should be in "closing state"');
res.statusCode = 500;
res.setHeader('content-type', 'text/plain');
res.end('Oops, there was a problem!\n');
} catch (er2) {
console.error('Error sending 500!', er2);
}
});
d.add(req);
d.add(res);
d.run(function() {
console.log('New request at: %s', req.url);
// error
setTimeout(function() {
flerb.bark();
});
});
});
server.listen(PORT);
Just run:
curl http://127.0.0.1:8080/ http://127.0.0.1:8080/
Output:
New request at: /
Trying to close the server
The server should not now accepts new requests, it should be in "closing state"
New request at: /
Trying to close the server
Error sending 500! [Error: Not running]
Now single request:
curl http://127.0.0.1:8080/
Output:
New request at: /
Trying to close the server
The server should not now accepts new requests, it should be in "closing state"
server is closed!
So with chrome doing 1 more request for the favicon for example, the server is not able to shutdown.
For now I'll keep using worker.kill() which makes the worker not to wait for the server to stops.
I ran into the same problem around 6 months ago, sadly don't have any code to demonstrate as it was from my previous job. I solved it by explicitly sending a message to the worker and calling disconnect at the same time. Disconnect prevents the worker from taking on new work and in my case as i was tracking all work that the worker was doing (it was for an upload service that had long running uploads) i was able to wait until all of them are finished and then exit with 0.