NodeJS send xhr response to unavailable client - node.js

I have a http-function that responses on a request as usual:
app.post('/file', function(res, req){
write(req.body.file, function(err, id){
if(!err)
res.send({id:id});
else
{
res.status(500);
res.send({ error: 500 });
}
});
});
I post a file that is beeing written to the filesystem. When the file was written, I send a response back to the client. Now the client lost the connection to the internet, the server can't send the response, throws an error and gets killed.
Error:
Error: Request aborted
at IncomingMessage.onReqAborted ....
....
http.js:689
throw new Error('Can\'t set headers after they are sent.');
How can I catch this exception?

To catch those errors you can res.on('error', function(err) {}) or req.socket.on('error', function(err) {}) to catch lower-level errors, although I think the lower-level errors do bubble up to the request/response object also.
I should also point out that your route parameters are flipped, it should be (req, res), not (res, req).

Related

Error: Can't set headers after they are sent. in node js

im new in node js, when im trying to sent data to database from react, on my node js got error 'can't set headers after they are sent. i've been searching for same like this problem, but it doesnt help me to solve this problem
i've tried using writeHead on the post(the second one)
but it doesn't help, is it bcs i sent the same image? i only got problem with sending the same image
app.post('/list', function(req, res){
const {namaCabor, descCabor, imgCabor } = req.body;
connectDb.collection('listCabangOlahraga').insertOne(req.body, function(err, res){
console.log(res.insertedCount +'data inserted');
});
res.send(req.body);
});
app.post('/add', function(req, res){
const {categoryName, categoryDesc, categoryImage, namaCabor, descCabor, imgCabor } = req.body;
connectDb.collection('listCategoryCabangOlahraga').insertOne(req.body, function(err, res){
console.log(res.insertedCount +'data inserted');
if(err) throw err;
});
res.writeHead(200, {'Content-Type' : 'application/json'});
res.end(JSON.stringify(req.body));
});
Quick analysis : Your code involves writing to MongoDB collection. It has an async callback. I guess the res.write() / res.send() should be included inside the callback?
If not, they get executed even before the DB operation is complete and we won't know if it succeeded or not.
app.post('/list', function(req, res){
const {namaCabor, descCabor, imgCabor } = req.body;
connectDb.collection('listCabangOlahraga').insertOne(req.body, function(err, res){
console.log(res.insertedCount +'data inserted');
// <----- Handle the error here and print response accordingly.
});
res.send(req.body); //Move this inside callback. Return error response if err encountered.
});
app.post('/add', function(req, res){
const {categoryName, categoryDesc, categoryImage, namaCabor, descCabor, imgCabor } = req.body;
connectDb.collection('listCategoryCabangOlahraga').insertOne(req.body, function(err, res){
console.log(res.insertedCount +'data inserted');
if(err) throw err;
// <----- Handle the error here and print response accordingly.
});
res.writeHead(200, {'Content-Type' : 'application/json'}); // Move this inside callback.
res.end(JSON.stringify(req.body)); //Write response from the callback.
});
Basically the error appears because res.write() / res.send() is called before setting the header
Also it's a good idea to have the res object renamed in either of the places (maybe the res (result) object in the MongoDB write callback can be renamed to avoid potential confusions with the res(response) object of the express route)
I guest that you have an error handler. In the /add route, it throws an error and your error handler will catch it. So you tried to set response header in both /add handler and error handler. The second handler will throw the error 'can't set headers after they are sent because response was already sent in the first handler(may be error handler or /add handler)
This error occur whenever node try to send http response after it has been sent,
e.g
{if(true){
res.send({})
}
res.send({
// this will throw that error because the pool is already close because the first res.send was executed.
});
}
However, in you case there is no such scenario visible in the code you posted,
but in in server.js, a method executed might have sent the response to the frontend and the pool is closed before the route controller finish processing causing the res.send or res.end in your code to throw the error.
So try to check other portion of your code base to debug this error.

How do I handle errors for get API request

I have written an API to view logs of my server in browser. I tried but not getting how to do error handling. Please show how will you do error handling. I am new to node.js
app.get('/logs', function(request, response, next) {
res.sendFile('file', 'path');
});
Error handling looks something like this below.
app.get('/logs', async function(req, res) {
let something;
try {
something = await "file processing";
} catch (error) {
res.status(500).json({ error: error.toString() });
}
res.json({ something });
});
when you are fetching API from other endpoint, you can use promise or async-await
when something goes wrong in the try statement, then error will be catched
if you want to make error deliberately, using new Error() in try statement
you can also study express error middleware when trying to handle route errors.

Express.js Routing error: Can't set headers after they are sent

I'm not really sure why I'm getting this error. It's a simple API built on express.js to be able to add and remove posts. The error occurs when I trigger the delete router. I've read that the error typically happens when there are two callbacks, however, I don't seem to be able find any double callbacks.
_http_outgoing.js:344
throw new Error('Can\'t set headers after they are sent.');
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)
at ServerResponse.header (/Users/bounty/Projects/_learning/react-express/node_modules/express/lib/response.js:718:10)
at ServerResponse.send (/Users/bounty/Projects/_learning/react-express/node_modules/express/lib/response.js:163:12)
at ServerResponse.json (/Users/bounty/Projects/_learning/react-express/node_modules/express/lib/response.js:249:15)
at /Users/bounty/Projects/_learning/react-express/server/routes/posts.js:86:9
at nextTickCallbackWith0Args (node.js:452:9)
at process._tickCallback (node.js:381:13)
Here is my posts.js router:
module.exports = function(router) {
var Post = require('../models/post.js');
// middleware for the api requests
router.use(function(req, res, next) {
// do logging
console.log('something is happening.');
next(); // make sure we go to our next route and don't stop here
});
// test route to make sure everything is working (accessed at GET http://localhost:8080/api)
router.get('/', function(req, res) {
res.json({ message: 'hooray! welcome to our api!' });
});
// all routes here
// routes that end in /posts
router.route('/posts')
// create a Post (accessed at POST http://localhost:7777/api/posts)
.post(function(req, res) {
var post = new Post();
post.postTitle = req.body.postTitle; // set the post name (comes from request)
// save post and check for errors
post.save(function(err) {
if (err)
res.send();
res.json({ message: 'post created!' });
});
})
// get all Posts (accessed at GET http://localhost:7777/api/posts)
.get(function(req, res) {
Post.find(function(err, posts) {
if (err)
res.send();
res.json(posts);
});
});
// routes that end in /posts for specific id
router.route('/posts/:post_id')
// get the post with that id
.get(function(req, res) {
Post.findById(req.params.post_id, function(err, post) {
if (err)
res.send(err);
res.json(post);
});
})
// update the post with that id
.put(function(req, res) {
Post.findById(req.params.post_id, function(err, post) {
if (err)
res.send(err);
post.postTitle = req.body.postTitle;
// save the post
post.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'post updated!' });
});
});
})
// deletes the post with that id
.delete(function(req, res) {
Post.remove({
_id: req.params.post_id
}, function(err, post) {
if (err) {
res.send(err);
}
res.json({ message: 'post deleted!' });
});
});
}
You need to add the 'return' so that you don't reply twice.
// save post and check for errors
post.save(function(err) {
if (err) {
return res.send();
}
res.json({ message: 'post created!' });
});
That particular error message is pretty much always caused because of a timing error in the handling of an async response that causes you to attempt to send data on a response after the response has already been sent.
It usually happens when people treat an async response inside an express route as a synchronous response and they end up sending data twice.
One place I see you would get this is in any of your error paths:
When you do this:
// save post and check for errors
post.save(function(err) {
if (err)
res.send();
res.json({ message: 'post created!' });
});
If post.save() generates an error, you will do res.send() and then you will do res.json(...) after it. Your code needs to have a return or an else so when there's an error you don't execute both code paths.
So, this can happen in Express when attempting to send res.end twice which res.send and res.json both do. In your if(err) block you'll want to return res.send() as res.send runs asynchronously and res.json is getting called as well. I'm wondering if you're getting an error in your delete route? Hope this helps.
Best!
You are using res.send() or res.json() twice in the same request
this send the headers first, followed by body of the response and then headers again.
req.next is usually not a function, next is rather passed as a third argument of the middleware. Use that if you want to drop to the next middleware. (assuming you are using Express framework)
Just for the sake of completeness I will also mention that:
Sometime problem may be in a the middleware you may be using by calling
app.use.
After checking for obvious errors as mentioned in previous answers:
You should remove all the app.use statement then reintroduce them one by one, to find problematic module.
If you are using res.send() inside any loop, then you need to break it after the use of res.send(). So that it won't allow resetting of the res headers again and again.
for e.g :
for(){
if(){
res.send();
break;
}
else(){
res.send();
break;
}
}
In my case this is the problem and I solved it like this.
Hope it may help someone in future.
Thanks
For a quick fix you can just check res.finished before calling res.send():
if (!res.finished)
res.send()

NodeJS SQLite Error Exception

I am currently trying to create a server using NodeJS to provide RESTful APIs for inserting records into a SQLite database. While I am able to retrieve records, I am having issues handling SQLite related errors (e.g. unique constraints):
function insertUser(name, password, response) {
db.run(insert_stmt, [name, password, new function(err) {
if (err != null) {
handleError(err, response);
}
else if (response != null) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("User registered.");
response.end();
}
}, function(err) {
handleError(err, response);
});
}
function handleError(err, response) {
console.log(err.message);
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Registration error.");
response.end();
}
The problem is that the code appears to be hitting both the second and the third function, as the response object appears to be closed whenever I try to create a response in the handleError method. In my browser, I am getting the "User registered." message as a response.
SQLITE_CONSTRAINT: UNIQUE constraint failed: Users.name, Users.phone_no
events.js:85
throw er; // Unhandled 'error' event
^
Error: write after end
at ServerResponse.OutgoingMessage.write (_http_outgoing.js:413:15)
at handleError (/Users/kli/Documents/Node.js/db.js:59:14)
at Statement.<anonymous> (/Users/kli/Documents/Node.js/db.js:39:3)
at Statement.replacement (/Users/kli/node_modules/sqlite3/lib/trace.js:20:31)
at Statement.replacement (/Users/kli/node_modules/sqlite3/lib/trace.js:20:31)
What is the correct way of handling errors in NodeJS? I tried using the process.on('uncaughtException', function(err) method, but I need the response object in order send a response to the client, indicating the error that has occurred.

Nodejs Using domain.dispose() causes server to respond with status 0

When I use domain.dispose() in Node.js expressjs based HTTP Server, the client making HTTP sees a response code of 0 (Could not get any response). If I remove domain.dispose() I receive 500 error with the desired error message. Below is my code
//Enable domains
app.use(function(req, res, next){
var createDomain = require('domain').create;
var domain = createDomain();
domain.add(req);
domain.add(res);
domain.run(function() {
next();
});
domain.on('error', function(e) {
//no further domain watch required
domain.dispose(); //if I remove this line status code of 500 is received on client, otherwise 0 or no response is received
next(e);
});
});
//Respond with 500 for Unhandled errors
app.use(function(err, req, res, next) {
// If the error object doesn't exists
if (!err) return next();
// Log it
req.log.error(err);
//console.error(err.stack);
try{
if(req.path && req.path.indexOf('/api/') === 0){
if(!res.headersSent){
console.log('responded with an error');
res.status(500).send({error: err.message});
console.log('responded with an error ACK');
}
return;
}
// Error page
res.status(500).render('500', {
error: err.stack
});
} catch(ex){
console.log('An error occured while responding 500');
req.log.error(ex);
}
});
Can anyone explain this or a better solution? Removing domain.dispose() may cause further exceptions, which may cause to re-enter the domain, and I do want to acknowledge client with the exception message as in my code.
This is expected behaviour of domains. Since you have explicitly added req and res to domain, so they are disposed as well. Don't use dispose, it does unexpected things. When you catch an error with domain the only sensible thing to do is to shutdown the process as quickly as possible.

Resources