Error: Cannot set headers after they are sent to the client - node.js

I code Promise.all , it load about 20 lines from db when running, it stops
My code
router.get('/', (req, res) => {
var cat = res.locals.lcCategories;
Promise.all([postModel.getTop10View(),postModel.getTop10latest()]).then(data => {
console.log(data);
return res.render('home');
}).catch(next);
});
Error:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:470:11)
at ServerResponse.header (C:\Users\tranh\Desktop\Web2-News\node_modules\express\lib\response.js:767:10)
at ServerResponse.send (C:\Users\tranh\Desktop\Web2-News\node_modules\express\lib\response.js:170:12)
at done (C:\Users\tranh\Desktop\Web2-News\node_modules\express\lib\response.js:1004:10)
at Immediate.<anonymous> (C:\Users\tranh\Desktop\Web2-News\node_modules\express-handlebars\lib\utils.js:26:13)
at runCallback (timers.js:705:18)
at tryOnImmediate (timers.js:676:5)
at processImmediate (timers.js:658:5)

I had the same issue, basically this error occurs when your api as already sent a response , but due to nodejs asynchronus ability or lost cycle it again sends a response , i think that promise.all is run and the request is still sent and when the promise.all returns from its loop it again sends a request.
Use await before promise.all
like
await Promise.all([postModel.getTop10View(),postModel.getTop10latest()]).then(data => {
console.log(data);
return res.render('home');
}).catch(next);

Related

NodeJs Express: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

Node express crashes when the response is in a setInterval. I want to test some things in the frontend when the response is delayed a bit. For this I have passed the response as a callback to the setInterval function in my nodeJs Express:
router.post('/survey', userMiddleware.isLoggedIn, (req, res ,next) => {
setInterval(() => {
res.status(200).send({
message: 'Upload success!'
});
}, 3000);
});
However, I then receive an error:
node:_http_outgoing:576
throw new ERR_HTTP_HEADERS_SENT('set');
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at new NodeError (node:internal/errors:371:5)
at ServerResponse.setHeader (node:_http_outgoing:576:11)
at ServerResponse.header (/node/node-express-jwt-test/node_modules/express/lib/response.js:794:10)
at ServerResponse.send (/node/node-express-jwt-test/node_modules/express/lib/response.js:174:12)
at ServerResponse.json (/node/node-express-jwt-test/node_modules/express/lib/response.js:278:15)
at ServerResponse.send (/node/node-express-jwt-test/node_modules/express/lib/response.js:162:21)
at Timeout._onTimeout (/node/node-express-jwt-test/routes/router.js:83:22)
at listOnTimeout (node:internal/timers:559:17)
at processTimers (node:internal/timers:502:7) {
code: 'ERR_HTTP_HEADERS_SENT'
}
Node.js v17.5.0
[nodemon] app crashed - waiting for file changes before starting...
What's going on?
You keep sending the response at an interval of 3000ms _ the delay is done but the it’s repeated
Use the ‘setTimeout(function, 3000)’ to send once
Read more about set timeout here https://www.w3schools.com/jsref/met_win_setTimeout.asp
So your code Should be like this:
router.post('/survey', userMiddleware.isLoggedIn, (req, res ,next) => {
setTimeout(() => {
res.status(200).send({
message: 'Upload success!'
});
}, 3000 );
});

creating custom token in cloud function after reteiving data from realtime database

i want to create custom token in cloud function but before that I want to check and compare timestamp from realtime database and with current time.if the timestamp is below 10 min then I want to create custom token and send back to client.please help me to achieve this.i am new to this cloud function firebase.
here is my code
export const authaccount = functions.https.onCall(async (data) => {
try {
const snap= await admin.database().ref("/register/"+data).get();
const time=snap.val().timestamp;
const now=new Date().getDate();
const reg=new Date(time).getDate();
const today=Math.abs(now-reg);
const daydiff=Math.floor(today/1000/60/60/24);
const nowminutes=new Date().getUTCMinutes();
const regminutes=new Date(time).getUTCMinutes();
const timediff=Math.abs(nowminutes-regminutes);
if (timediff<10 && daydiff==0) {
try {
admin.auth().createCustomToken(data).then((customtoken)=>{
console.log("auth created"+" "+timediff+" "+daydiff+" "+customtoken);
return customtoken;
});
} catch (err1) {
throw new functions.https.HttpsError("unknown", err1.message, err1);
}
} else {
console.log("else "+" "+now+" "+reg+" "+time+" "+daydiff);
}
} catch (err2) {
throw new functions.https.HttpsError("unknown", err2.message, err2);
}
});
2:53:20.626 AM
authaccount
Error: Process exited with code 16 at process.<anonymous> (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/invoker.js:275:22) at process.emit (events.js:314:20) at process.EventEmitter.emit (domain.js:483:12) at process.exit (internal/process/per_thread.js:168:15) at Object.sendCrashResponse (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/logger.js:37:9) at process.<anonymous> (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/invoker.js:271:22) at process.emit (events.js:314:20) at process.EventEmitter.emit (domain.js:483:12) at processPromiseRejections (internal/process/promises.js:209:33) at processTicksAndRejections (internal/process/task_queues.js:98:32)
2:53:19.559 AM
authaccount
Error: The caller does not have permission; Please refer to https://firebase.google.com/docs/auth/admin/create-custom-tokens for more details on how to use and troubleshoot this feature. at FirebaseAuthError.FirebaseError [as constructor] (/workspace/node_modules/firebase-admin/lib/utils/error.js:44:28) at FirebaseAuthError.PrefixedFirebaseError [as constructor] (/workspace/node_modules/firebase-admin/lib/utils/error.js:90:28) at new FirebaseAuthError (/workspace/node_modules/firebase-admin/lib/utils/error.js:149:16) at Function.FirebaseAuthError.fromServerError (/workspace/node_modules/firebase-admin/lib/utils/error.js:188:16) at /workspace/node_modules/firebase-admin/lib/auth/token-generator.js:114:53 at processTicksAndRejections (internal/process/task_queues.js:97:5) at async Promise.all (index 1)
2:53:19.558 AM
authaccount
Unhandled rejection
2:53:19.469 AM
authaccount
Function execution took 1386 ms, finished with status code: 200
please help to solve this problem. i don't know where I am making the mistake.
You will need to make sure your Firebase Admin sdk is initiated and running before the function proceeds
if (firebase.apps.length === 0) {
firebase.initializeApp();
}
Resource: https://firebase.google.com/docs/admin/setup#initialize-without-parameters
I doubt you have modified the IAM permissions on your service account but as the comment suggested: https://firebase.google.com/docs/auth/admin/create-custom-tokens#service_account_does_not_have_required_permissions
Once that is confirmed to be working - you will need to ensure that the onCall data is a string and not null, some simple health checks can help you debug your process
console.log(typeof data);
console.warn("Data", data);
from there I would also debug your date times and the realtime database result, these are async and will require the promise to be resolved before you can use it.
Update:
All cloud functions should return a response to the client
onCall uses promises on the client and supports a 'return Object'
example:
return {
token: myCustomToken,
possible: otherValue
};
for comparison, onRequest uses fetch like responses and supports codes
response.status(500)
response.send({name:value})
return;
Source:
https://firebase.google.com/docs/functions/callable#sending_back_the_result
Source:
https://firebase.google.com/docs/functions/http-events#using_express_request_and_response_objects
Update:
all paths and promises need to resolve correctly, this includes awaiting promises to resolve and returning their result or storing the result for any secondary processing - I suggest cleaning up the code, remove the try/catch and use .then().catch()
Example:
if (timediff<10 && daydiff==0) {
return await admin.auth().createCustomToken(data)
.then((customtoken)=>{
console.log("auth created"+" "+timediff+" "+daydiff+" "+customtoken);
return customtoken;
})
.catch (err) {
return new functions.https.HttpsError("unknown", err.message, err);
}
}
else {
console.log("else "+" "+now+" "+reg+" "+time+" "+daydiff);
return "else "+" "+now+" "+reg+" "+time+" "+daydiff;
}

Some error occures after send request to the function url

I set up a one firebase function to send messages to my bot. But when firebase gets request I can see that some error occurred.
FetchError: request to https://api.telegram.org/bot<BOT-TOKEN>/getMe failed, reason: getaddrinfo EAI_AGAIN api.telegram.org:443
at ClientRequest.<anonymous> (/srv/node_modules/node-fetch/lib/index.js:1453:11)
at emitOne (events.js:116:13)
at ClientRequest.emit (events.js:211:7)
at TLSSocket.socketErrorListener (_http_client.js:401:9)
at emitOne (events.js:116:13)
at TLSSocket.emit (events.js:211:7)
at emitErrorNT (internal/streams/destroy.js:66:8)
at _combinedTickCallback (internal/process/next_tick.js:139:11)
at process._tickDomainCallback (internal/process/next_tick.js:219:9)
and
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:491:11)
at ServerResponse.setHeader (_http_outgoing.js:498:3)
at ServerResponse.header (/worker/node_modules/express/lib/response.js:767:10)
at ServerResponse.contentType (/worker/node_modules/express/lib/response.js:595:15)
at ServerResponse.sendStatus (/worker/node_modules/express/lib/response.js:357:8)
at /srv/index.js:30:13
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:229:7)
But secound one I suppose does not influence on the result.
As a result, I don't get any message to my to Bot.
The next script that i use:
const functions = require('firebase-functions');
const telegraf = require('telegraf');
const axios = require('axios');
const bot = new telegraf('<BOT-TOKEN>')
bot.start((ctx) => ctx.reply('Welcome!'))
bot.help((ctx) => ctx.reply('Send me a sticker'))
bot.on('sticker', (ctx) => ctx.reply('👍'))
bot.hears('hi', (ctx) => ctx.reply('Hey there'))
bot.launch()
exports.helloWorld = functions.https.onRequest((request, res) => {
const token = '<BOT-TOKEN>';
const url = `https://api.telegram.org/bot${token}/sendMessage`;
axios.post(url, {
chat_id: '154866113',
text: "just do it!"
})
.then(function (response) {
console.log(response);
res.send({ status: "O"});
return 'ok';
})
.catch(function (error) {
console.log(error);
res.sendStatus(500);
});
res.send("Hello from Firebase!");
});
The getaddrinfo EAI_AGAIN error means that you need to switch to the "Flame" or "Blaze" pricing plan.
As a matter of fact, the free "Spark" plan "allows outbound network requests only to Google-owned services". See https://firebase.google.com/pricing/ (hover your mouse on the question mark situated after the "Cloud Functions" title)
The telegram API is not a Google-owned service, so you need to switch to the "Flame" or "Blaze" plan.
I'm guessing the answer to the EAI_AGAIN error is due to a malformed URI. Are you sure https://api.telegram.org/bot<BOT-TOKEN>/getMe is the correct URI and is accessible from where ever this script is being run from?
The second error is due to you calling the res.send() method more than once. Express res objects wrap Node's ServerResponse object, and once the connection is closed via write or end, it cannot be sent again. Try removing the res.send("Hello from Firebase!"); section of your code and coming back.

Node Express js Unhandled rejection Error [ERR_HTTP_HEADERS_SENT]

I am new for node js. I am trying to insert the data to database, before that I did some validation for checking username already exist in database. Please see the coding which is used by me.
var express = require("express");
var router = express.Router();
var models = require("../models");
const { check, validationResult } = require('express-validator/check');
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource - merchant');
});
/* POST ADD USERS. */
router.post('/add-merchant', [
check('name').not().isEmpty(),
], (req, res, next) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.json({ errors: errors.array()});
}
console.log("error passed")
models.merchants.findOne({ where: {name: req.body.name}}).then((merchant) => {
if(merchant) {
throw new Error("Username already exists")
}
models.merchants.create(req.body).then((merchant) => {
res.json(merchant)
});
})
} catch (error) {
res.json({"status": "error", "message": error.message})
}
});
module.exports = router;
I am getting below error while running the above code
Unhandled rejection Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:470:11)
at ServerResponse.header (/home/assistanz/Desktop/node/gb360/node_modules/express/lib/response.js:767:10)
at ServerResponse.send (/home/assistanz/Desktop/node/gb360/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/home/assistanz/Desktop/node/gb360/node_modules/express/lib/response.js:267:15)
at models.merchants.create.then (/home/assistanz/Desktop/node/gb360/routes/merchant.js:33:21)
at tryCatcher (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/promise.js:512:31)
at Promise._settlePromise (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/promise.js:569:18)
at Promise._settlePromise0 (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/promise.js:614:10)
at Promise._settlePromises (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/promise.js:694:18)
at _drainQueueStep (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/async.js:138:12)
at _drainQueue (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/async.js:131:9)
at Async._drainQueues (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/async.js:147:5)
at Immediate.Async.drainQueues [as _onImmediate] (/home/assistanz/Desktop/node/gb360/node_modules/bluebird/js/release/async.js:17:14)
at runCallback (timers.js:705:18)
at tryOnImmediate (timers.js:676:5)
at processImmediate (timers.js:658:5)
Please help anyone to solve this issue.
Thanks in advance.
this error occurs because you return the response and something is remain to load
you have to remove console.log("error passed") or you can put it before return statement..
and write return statement for every res.json statement
as
return res.json({})
HTTP uses a cycle that requires one response per request. When the client sends a request the server should send only one response back to client. So modify the code as below,
models.merchants.findOne({ where: { name: req.body.name } }).then((merchant) => {
if (merchant) {
throw new Error("Username already exists")
} else {
models.merchants.create(req.body).then((merchant) => {
res.json(merchant)
});
}
})

Cannot set headers after they are sent to the client - Node/Mongoose/Express

I am working on an fantasy soccer app for my friends and I, but I am getting this age old error and it doesn't seem like any of the other questions answered on here really fit my situation. In the first block of code below, the console.log is returning the correct data, so I am very certain that the res.json(populatedClub) should be working just fine. I cannot find anywhere else in my code that is triggering another res.send() or res.json() in this chain of events.
Is anybody else able to see what I am not?
My route:
fantasyClubRouter.get('/:userId',
(req, res) => {
FantasyClub
.findOne({manager: req.params.userId})
.populate({
path: 'manager',
model: 'User'
})
.exec((error, populatedClub) => {
if (error) {
return () => {throw new Error(error)};
}
console.log('populatedClub:', populatedClub);
res.json(populatedClub);
})
.catch(error => {
throw new Error(error);
});
}
);
The error stack:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:471:11)
at ServerResponse.header (/home/ubuntu/workspace/node_modules/express/lib/response.js:767:10)
at ServerResponse.send (/home/ubuntu/workspace/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/home/ubuntu/workspace/node_modules/express/lib/response.js:267:15)
at FantasyClub.findOne.populate.exec (/home/ubuntu/workspace/server/fantasyClub-routes.js:18:11)
at /home/ubuntu/workspace/node_modules/mongoose/lib/model.js:4187:16
at (anonymous function).call (/home/ubuntu/workspace/node_modules/mongoose/lib/query.js:3128:7)
at process.nextTick (/home/ubuntu/workspace/node_modules/mongoose/lib/query.js:2019:28)
at process._tickCallback (internal/process/next_tick.js:61:11)
Emitted 'error' event at:
at /home/ubuntu/workspace/node_modules/mongoose/lib/model.js:4189:13
at (anonymous function).call (/home/ubuntu/workspace/node_modules/mongoose/lib/query.js:3128:7)
at process.nextTick (/home/ubuntu/workspace/node_modules/mongoose/lib/query.js:2019:28)
at process._tickCallback (internal/process/next_tick.js:61:11)
I figured out what I had done wrong, and it was so simple that I'm almost embarrassed to admit it, but here it goes.
I updated from an older version of Mongoose and forgot to update my code accordingly. Always make sure your code matches what the docs say for the version of the library you are using.
This is the working code:
fantasyClubRouter.get('/:userId',
(req, res) => {
FantasyClub
.findOne({manager: req.params.userId})
.populate({
path: 'manager',
model: 'User'
})
.then(populatedClub => {
res.json(populatedClub);
})
.catch(error => {
throw new Error(error);
});
}
);

Resources