A specific URL causes axios nuxt module to not run callback - javascript

So I have setup two buttons called "Confirm" and "Delete" on my nuxt.js page. Each button, when clicked, will run confirm() and delete() respectively. The code for the two functions are nearly identical, the only difference being that the URLs are different. When running delete(), it performs a GET request with axios and the callback is run perfectly and does what I want it to do. However, when running confirm(), it performs the request but the callback isn't run.
I thought maybe the API server isn't responding. However, when I checked the logs, the response is actually being sent.
1zcu ——> GET /api/pending/delete/5d554a5d9ddb8079158eefcc
1zcu <—— 200 OK 15 B application/json; charset=utf-8 (<—> 326.1 ms)
yefy ——> GET /api/pending/confirm/5d554a5c9ddb8079158eefcb
yefy <—— 200 OK 14 B application/json; charset=utf-8 (<—> 540.9 ms)
So I tried changing the URL in the confirm() function to match the one in the delete() function and sure enough, it started working.
Functions
confirm(id) {
this.setConfirming(id);
const url = CON_URL + id;
this.$axios.$get(url).then((res) => {
if (!res.error) {
console.log(res)
this.refresh();
}
});
},
discard(id) {
this.setDeleting(id);
const url = DEL_URL + id;
this.$axios.$get(url).then((res) => {
if (!res.error) {
console.log(res)
this.refresh();
}
});
},
URLs
const DEL_URL = "/api/pending/delete/";
const CON_URL = "/api/pending/confirm/";
Buttons
<td v-if="!enquiry.isConfirming"><button v-on:click="confirm(enquiry._id)" class="button is-primary">Confirm</button></td>
<td v-if="!enquiry.isDeleting"><button v-on:click="discard(enquiry._id)" class="button is-danger">Discard</button></td>
Express endpoints
router.get('/delete/:id', (req, res) => {
Pending.findOneAndDelete({ _id: req.params.id }, (err, pending) => {
if (err) {
res.json({ error: true });
} else {
res.json({ error: false });
}
});
});
router.get('/confirm/:id', (req, res) => {
Pending.findOneAndDelete({ _id: req.params.id }, (err, pending) => {
if (err) {
res.json({ error: true });
} else {
const confirmed = new Booking(pending);
confirmed.save((err, result) => {
if (err) {
res.json({ error: true });
} else {
res.json({ error: false });
}
});
}
});
});

Promise.then is only executed if the task completed without exception. You may also need to attach a callback for the error condition with Promise.catch:
this.$axios.$get(url)
.then((res) => {
console.info(res);
})
.catch((err) => {
console.error(err);
})
.finally(() => {
console.info('done');
});

Related

UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the clien

I get error: "UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client",
guessing that the problem is with promises, but I don't understand how to fix it.
How do I fix my code to avoid this error, but keep the logic and work with the database?
router.post("/addNote", (req, res) => {
let currentTime = new Date();
currentTime.setUTCHours(currentTime.getUTCHours() + 3);
const post = new PostModel({
title: req.body.inputHeader,
text: req.body.inputText,
author: req.body.author,
createdAt: currentTime
});
post.save().then(() => {
res.json({status: "saved"});
})});
router.get("/getNotes", (req, res) => {
PostModel.find().sort({createdAt: 'descending'}).then( (err, notes) => {
if (err)
res.json(err);
res.json(notes);
});
});
router.delete("/deleteNote/:id", (req, res) => {
PostModel.deleteOne(
{
_id: req.params.id
}
).then((notes) => {
if (notes)
res.json({status: "deleted"});
res.json({status: "error while deleting"});
});
});
router.put("/updateNote/:id", (req, res) => {
PostModel.findByIdAndUpdate(
req.params.id,
{
$set: req.body
},
err => {
if (err)
res.send(err);
res.send({status: "updated"})
}
).then((notes) => {
if (notes)
res.json({status: "update"});
res.json({status: "error while updating"});
});
});
router.get("/getNote", (req, res) => {
PostModel.findOne({ _id: req.params.id}).then(post => {
if (!post){
res.send({error: "not found"});
} else {
res.json(post)
}
});
});
router.post("/authorize", (req, res) => {
// bcrypt.hash ("", saltRounds, (err, hash) => {
// console.log(hash);
// });
let resultAuthorization = false;
if (req.body.login === authorization.login) {
resultAuthorization = bcrypt.compareSync(req.body.password, authorization.password);
}
if (resultAuthorization)
res.json({statusAuthorization: "correct"});
res.json({statusAuthorization: "incorrect"});
});
module.exports = router;
The problem is that you are calling res.json several times in one handler. When calling it a second time a response has already been sent so you can not send another response.
As tkausl already pointed out you are missing elses so that res.json is being called once.
You need to change your handlers similar to the /getNote handler.
The handler for the endpoint deleteNode/:id for example has to be changed to this:
router.delete("/deleteNote/:id", (req, res) => {
PostModel.deleteOne(
{
_id: req.params.id
}
).then((notes) => {
if (notes)
res.json({status: "deleted"});
else
res.json({status: "error while deleting"});
});
});
This else also needs to be added in /getNotes and /authorize.
The reason is you're trying to send a response more than once. Once the response is returned, if the program sends a response again, this error occurs.
The reason for the problem is that you do not return the current function after the if condition.
Let me explain with some codes
router.get("/getNotes", (req, res) => {
PostModel.find().sort({createdAt: 'descending'}).then( (err, notes) => {
if (err) {
res.json(err);
console.log('We encountered an error and sent the error as a response. But our function still continue...');
}
res.json(notes);
console.log('We tried to sent successfull response but function still continue');
});
});
So after the response, you should end the function or make sure that you do not call any other response function in the ongoing code stream/flow.
Lets fix your code.
router.get("/getNotes", (req, res) => {
PostModel.find().sort({createdAt: 'descending'}).then( (err, notes) => {
if (err) {
return res.json(err);
// It is not will be continued because the function returned with response.
}
return res.json(notes);
console.log('No console output')// It is will not be called because function returned.
});
});

how to stop function if a fetch request fails

i'm building an email form with Google Captcha v3.
I want that if the score is less then 1 the rest of the function (request) should end.
but the problem is that if I add a return statement to my fetch request than it just goes out of the .then() function and doesn't stop the request.
Here's the code:
app.post(
"/mail",
(req, res) => {
const url = `https://www.google.com/recaptcha/api/siteverify?secret=${process.env.SECRET_KEY}&response=${req.body.token}`;
fetch(url, {
method: "post",
})
.then((response) => response.json())
.then((google_response) => {
console.log(google_response);
if ((google_response.success = false || google_response.score < 1)) {
console.log("ROBOT ALERT");
res.status(422).json({
captcha: "Robot verification failed. Try again later",
});
return; //------------here I want to stop the continuation of the request----
}
return;
})
.catch((error) => {
console.log(error);
res.json({ captcha: "An unknown error occurred. Try again later" });
});
// Finds the validation errors in this request and wraps them in an object with handy functions
const errors = validationResult(req);
if (!errors.isEmpty()) {
console.log(errors);
return res.status(422).json({ errors: errors.array() });
}
//If everything is ok then end request here.
res.json({ success: true });
}
})
Just do everything inside the then:
fetch(url, options).then(response => response.json().then(data => {
// do everything here
})).catch(e => {
// handle error
})
You can use return inside the if statement to stop executing the function once the if statement is triggered:
app.post("/mail", (req, res) => {
fetch(url, options)
.then((response) => response.json())
.then((googleResponse) => {
if ((google_response.success = false || google_response.score < 1)) {
console.log("ROBOT ALERT");
return res.status(404).send({ captcha: "Robot verification failed. Try again later" });
// Should stop here if condition is triggered
}
// Continue here if the condition is not triggered
});
});

Node JS throwing cannot set headers after they are sent to the client, after using mongoose.removeOne

I have a method that deletes products and before it does it check if the user who is trying to delete the product is the user who created it. When i execute it with Insomnia it successfully removes the product but i get an error on the console saying cannot set headers after they are sent to the client.
My method:
exports.deleteProduct = (req, res) => {
const id = req.params.productId;
Product.deleteOne({ _id: id, userId: req.user._id }, () => {
return res.status(401).json("Not authorized");
})
.then(() => {
return res.status(200).json("Product deleted");
})
.catch((err) => {
return res.status(500).json({
error: err,
});
});
};
I'm pretty sure this is happening because I'm chaining a .then() and .catch() after executing it.
I tried to do this but it didn't work because the err parameter that I'm sending to the callback function is null.:
exports.deleteProduct = (req, res) => {
const id = req.params.productId;
Product.deleteOne({ _id: id, userId: req.user._id }, (err) => {
if (err) {
return res.status(401).json("Not authorized");
}
return res.status(200).json("Product deleted");
});
};
When i tried this second approach I always got the 200 status, meanwhile the product didn't delete.
Any idea how to deal with this?
You can try something like this:
Product.deleteOne({ _id: id, userId: req.user._id }, (err, result) => {
if(err) {
return "something"
}
return "something else"
});
or: in async / await way
try {
await Product.deleteOne({ _id: id, userId: req.user._id });
} catch (err) {
// handle error here
}
By the way, why you are passing userId at the deleteOne method?

error in getting the response, if nodejs server send response after some delay

I am trying to upload the image, and then nodeJS server send the path of that image folder back as a response.
But When I sending the response after performing some task, nothing happening on angular-side.
this is my component.ts file.
uploadImage() {
const formData = new FormData();
formData.append('photo', this.image);
const obj$ = this.userService.uploadData(formData);
obj$.subscribe(data => {
console.log(data); //// nothing happening.
if (data.success) {
this.uploadForm.patchValue({
document: data.url
});
}
});
}
and my service.ts
uploadData (uploadImage) {
return this.http.post<UploadPhoto>('/user/upload', uploadImage);
}
and my app.js
router.post('/upload' ,upload.single('photo'), (req,res) => {
console.log(req.file);
const body = req.file;
cloudinary.uploader.upload(body.path, (err, result) => {
if (err) {
console.log(err);
return;
}
console.log(result);
res.status(200).json({
url: result.url,
success: true
});
});
});
But when I am sending response without performing any task, it works fine like
router.post('/upload' ,upload.single('photo'), (req,res) => {
console.log(req.file);
const body = req.file;
res.status(200).json({
url: 'hello',
success: true
})
});
I don't know why is this happening.
Please someone help me.
When an error occurs in your uploader you're returning the error to the console and then ending execution. If there is an error in the asynchronous method you must pass it to the next() function so that express can handle it.
router.post('/upload' ,upload.single('photo'), (req,res, next) => {
console.log(req.file);
const body = req.file;
cloudinary.uploader.upload(body.path, (err, result) => {
if (err) {
console.log(err);
next(err);
}
else {
console.log(result);
res.status(200).json({ url: result.url, success: true });
}
});
});

What cause "Error: Uncaught (in promise): Response with status:200 for Url:null" to show up?

I'm accessing a Mongo database through NodeJS and Express as below:
var MongoClient = require('mongodb').MongoClient;
...
app.get("/app/visits", function (req, res, next) {
console.log("get visits");
MongoClient.connect('mongodb://localhost:27017/db', function (err, db) {
if (!err) { console.log("We are connected"); }
visits = db.collection('visits', function (err, collection) { });
visits.find().toArray(function (err, user) {
this.user = JSON.stringify(user);
if (err) { throw err; } else console.dir(this.user);
});
res.send(this.user);
});
});
In the browser this works fine. If I change res.send(this.user); to res.status(301).send(this.user); the status is also changed.
But the problem, Angular 2 with native script code returns the error:
getActualVisits()
{
return this.http.get("http://localhost:1234/app/visits").map(response => response.json())
}
I have no idea WHY after 7 hours of trying repair that.
Method getActualVisits() is calling from:
getActualSpecialization() {
let v = this.getActualVisits();
...
}
You need to call .subscribe after .map in order to observe the values that are returned.
getActualVisits() {
return this.http.get("http://localhost:1234/app/visits")
.map(response => response.json())
.subscribe(
data => this.actualVisits = data,
err => this.logError(err),
() => console.log('get actual visits complete')
);
}
See the following docs for more information https://auth0.com/blog/2015/10/15/angular-2-series-part-3-using-http/

Categories

Resources