How to prevent Node.js sending success header to ajax post request - ajax

I am trying to send a success status to the ajax request using res.end('{"success" : "Updated Successfully", "status" : 200}'); but run into this error: Error: Can't set headers after they are sent. Basically when the user data is saved on the server I want ajax to refresh the page, although, I think somewhere in this in the app.post a success message is being sent before I try to manually do it. How can I prevent any success message being sent to the ajax post request so I can do it manually.
app.post('/signup', function (req, res) {
var userDetails = User({
username: req.body.username,
email: req.body.email,
password: bcrypt.hashSync(req.body.password1, bcrypt.genSaltSync(10))
});
User.findOne({
$or: [{
'username': req.body.username
}, {
'email': req.body.email
}]
}, function (err, user) {
if (user) {
if (allClients.indexOf(req.body.socket)) {
if (user.username === req.body.username) {
io.to(req.body.socket).emit('userInfo', 'That username is already in use.');
} else {
}
if (user.email === req.body.email) {
io.to(req.body.socket).emit('userInfo', 'That email is already in use.');
} else {
}
} else {
console.log('timeout error 822')
}
} else {
req.login(userDetails, function (err) {
if (!err) {
userDetails.save(function (err) {
if (err) throw err;
res.end('{"success" : "Updated Successfully", "status" : 200}');
res.redirect('/');
});
} else {
console.log(err)
}
})
}
if (err) {
return done(err);
}
});
});
This is my ajax request
$("#form1").submit(function(e) {
e.preventDefault();
$.ajax({
datatype: "json",
type: "POST",
url: '/signup',
data: $(this).serialize(),
success: function(result)
{
console.log(result);
if(result.status == 200){
window.location.reload(true);
}
}
});
});

I think the problem is in the code:
res.end('{"success" : "Updated Successfully", "status" : 200}');
res.redirect('/');
Replace the above with only
res.status(200).send({"success" : "Updated Successfully", "status" : 200})
res.redirect is to take the user to another page(it calls a get route). The error you are getting is because node is confused between sending the response back to ajax or to redirect.

Related

Sending a json object with ajax post

Im working on a project, where we try to exchange different parameters between the UI and a RestAPI via AJAX. The RestAPI defines how the data has to look:
I tried to solve it this way:
$(document).ready(function(){
$("#submit").click(function(){
var credentials = [
{user_name: $("#uname").val(),
password: $("#pwd").val()
}
];
alert(credentials);
$.ajax({
url:"../rest/user/login",
type:"POST",
data:JSON.stringify({credentials: credentials}),
success: function(){
window.location.href = "startrackhome.html";
},
error: function error(response){
try{
var json = JSON.parse(response.responseText);
if(typeof json.message === 'undefined'){
throw new Error("Response json has no message");
}
else{
alert(json.message);
}
}
catch(ex){
alert("unexpected error (code:" + response.status +")");
}
}
});
});
});
The alert shows this: [object Object]
And I always get an error message (error: 400), which means that I mus have made a mistake and I think the format I'm sendig is wrong but I dont know how to fix it.
I hope you can help me! :)
I made some changes to your code :
// credentials is an object
var credentials = {
user_name: $("#uname").val(),
password: $("#pwd").val()
}
alert(credentials);
$.ajax({
// check this url seems a bit off
url: "../rest/user/login",
type: "POST",
data: {
credentials: credentials
},
success: function() {
window.location.href = "startrackhome.html";
},
error: function error(response) {
try {
var json = JSON.parse(response.responseText);
if (typeof json.message === 'undefined') {
throw new Error("Response json has no message");
} else {
alert(json.message);
}
} catch (ex) {
alert("unexpected error (code:" + response.status + ")");
}
}
});
in my case it makes this request :
fetch("https://stackoverflow.com/posts/rest/user/login", {
"headers": {
"accept": "*/*",
"accept-language": "",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"sec-ch-ua": "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"102\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Linux\"",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"x-requested-with": "XMLHttpRequest"
},
"referrer": "https://stackoverflow.com/posts/72620005/edit",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": "credentials%5Buser_name%5D=test&credentials%5Bpassword%5D=test",
"method": "POST",
"mode": "cors",
"credentials": "include"
});
credentials[user_name]: test
credentials[password]: test
which seems good, if the server needs a json, you can stringify the credentials, which gives this paylaod :
credentials: {"user_name":"test","password":"test"}

Does Vue.JS work with AJAX http calls?

I am trying to do the following from my HTML:
var vm = new Vue({
el: '#loginContent',
data: {
main_message: 'Login',
isLoggedIn: false,
loginError: '',
loginButton:'Login'
},
methods: {
onLogin: function() {
//this.$set(loginSubmit, 'Logging In...');
var data = {
email: $('#email').val(),
password: $('#password').val(),
};
$.ajax({
url: '/api/login',
data: data,
method: 'POST'
}).then(function (response) {
if(response.error) {
console.err("There was an error " + response.error);
this.loginError = 'Error';
} else {
//$('#loginBlock').attr("hidden",true);
console.log(response.user);
if(response.user) {
this.isLoggedIn = true;
} else {
this.loginError = 'User not found';
}
}
}).catch(function (err) {
console.error(err);
});
}
}
});
Basically user presses the login button, onLogin method is called that sends a post to my API. The post is working fine and I do get the response back in the .then() promise.
But, trying to do things like this.isLoggedIn = true; does not update my DOM with what I am expecting the HTML to do when the user logs in.
Could be that I am in some sort of background thread (sorry, mobile developer here) when I get the response in the promise and it can't find the "vm" instance?
Thanks
It is probably happening because your this is not pointing to correct scope, scope of this changes inside an $.ajax call, so you just have to do something like following:
methods: {
onLogin: function() {
//this.$set(loginSubmit, 'Logging In...');
var data = {
email: $('#email').val(),
password: $('#password').val(),
};
var that = this
$.ajax({
url: '/api/login',
data: data,
method: 'POST'
}).then(function (response) {
if(response.error) {
console.err("There was an error " + response.error);
that.loginError = 'Error';
} else {
//$('#loginBlock').attr("hidden",true);
console.log(response.user);
if(response.user) {
that.isLoggedIn = true;
} else {
that.loginError = 'User not found';
}
}
}).catch(function (err) {
console.error(err);
});
}
}
I would propose another method use ES6 Arrow Functions like '=>'. It is simple and do not need extra variable.Like following:
$.ajax({
url: '/api/login',
data: data,
method: 'POST'
}).then((response) => {
if(response.error) {
console.err("There was an error " + response.error);
this.loginError = 'Error';
} else {
//$('#loginBlock').attr("hidden",true);
console.log(response.user);
if(response.user) {
this.isLoggedIn = true;
} else {
this.loginError = 'User not found';
}
}
}).catch(function (err) {
console.error(err);
});
You might want to take a look at axios. I used $.ajax and got it working, but found axios and prefer axios over the ajax library.

AJAX POST request never completes. Data posts to server

I am sending a post request via AJAX. The data successfully posts but the AJAX call never completes. Backbone on the front; Node on the back. I am including the save function from my backbone view and the express route.
save: function(event) {
event.preventDefault();
console.log( 'You signed up for ' + this.model.get('name'));
var name = this.model.get('name');
var courseDay = this.model.get('courseDay');
var time = this.model.get('time');
var location = this.model.get('location');
jQuery.post("/test/signups", {
"name" : name,
"courseDay" : courseDay,
"time" : time,
"location" : location,
}, function (data, textStatus, jqXHR) {
console.log("Post response:");
console.dir(data);
console.log(textStatus);
console.dir(jqXHR);
});
}
Route:
app.post('/test/signups', isLoggedIn, function (req, res){
User.findOne({'_id': req.user.id }, function(err, user) {
if (err)
return done(err);
if (user) {
user.signup.name = req.body.name;
user.signup.courseDay = req.body.courseDay;
user.signup.time = req.body.time;
user.signup.location = req.body.location;
user.signup.modified = req.body.modified;
user.update({$push: { "signup" :
{ name: user.signup.name,
courseDay: user.signup.courseDay,
time: user.signup.time,
location: user.signup.location,
modified: user.signup.modified
}
}},{safe:true, upsert:true},function(err){
if(err){
console.log(err);
} else {
console.log("Successfully added" + user.signup);
}
});
}
});
});
Your server side code needs to send a response. Try something like below. Note I try to cover all cases of an error, user not found, and user found.
app.post('/test/signups', isLoggedIn, function (req, res){
User.findOne({'_id': req.user.id }, function(err, user) {
if (err) {
return res.status(500).send(err);
}
if (user) {
user.signup.name = req.body.name;
user.signup.courseDay = req.body.courseDay;
user.signup.time = req.body.time;
user.signup.location = req.body.location;
user.signup.modified = req.body.modified;
user.update({$push: { "signup" :
{ name: user.signup.name,
courseDay: user.signup.courseDay,
time: user.signup.time,
location: user.signup.location,
modified: user.signup.modified
}
}},{safe:true, upsert:true},function(err){
if(err){
return res.status(500).send(err);
}
console.log("Successfully added" + user.signup);
res.send(user);
});
} else {
res.status(404).send();
}
});
});

Symfony2 redirect in an ajax action

I am using Symfony2 and in my register.html.twig, I have:
var registerdata= {
"email": email,
"pwd": pwd,
"phoneNum": phoneNum
};
$.ajax({
type: 'POST',
url: "register",
data: registerdata,
success: function(msg){
alert("OK! ");
},
error: function(XmlHttpRequest,textStatus, errorThrown){
alert("Failed! ");
}
});
In my controller, after inserting those data into the database, I want to redirect to the login page, and I have code like this:
try
{
$this -> insertData($account);
return $this ->redirect($this ->generateUrl('login'));
}
catch (Exception $e)
{
return new response('Message: '. $e->getMessage());
}
It does not work, however. How should I handle the problem?
You need another more step in your jQuery code. When the server returns a redirect response, you should redirect the client using javascript:
var registerdata= {
"email": email,
"pwd": pwd,
"phoneNum": phoneNum
};
$.ajax({
type: 'POST',
url: "register",
data: registerdata,
success: function(msg){
alert("OK! ");
},
error: function(XmlHttpRequest,textStatus, errorThrown){
alert("Failed! ");
},
complete: function(xhr)
{
if (xhr.status == 302) {
location.href = xhr.getResponseHeader("Location");
}
}
});
Of course this is far from ideal.

Unauthorized AJAX request succeeds

I have following controller method:
[HttpPost]
[Authorize(Roles="some_role_actual_user_is_NOT_in")
public ActionResult AJAXMethod()
{
return Json(new { message = "server message");
}
and page with script:
function sendReq()
{
$.ajax({
type: "POST",
data: { somedata: "somedata" },
url: "/Path/To/AJAXMethod",
success: onAJAXSuccess,
error: onAJAXError
});
}
function onAJAXSuccess(response, status, xhr)
{
alert("success: " + response.message);
alert(status);
}
function onAJAXError(xhr,status,error)
{
alert("error: " + status);
alert(error);
}
When I call sendReq with user not in the authorized role the AJAX call still suceed - callback onAJAXSuccess is called, but response.message is undefined.
This is correct behaviour. The success of an AJAX call is only determined by the fact the the server responded with a 200 OK. You will need to interrogate the returned response yourself to ensure it is in the format you expect.
For example:
if (typeof response.message != "undefined" && response.message != "") {
// it worked
}
else {
// didn't work || user did not have access.
}

Resources