I am using AngularJs with NodeJs.
I have a scenario when upon a successful HTTP POST request, I need to redirect the user.
In the client through AngularJS, I make a HTTP POST request to a route:
$http.post('/aPath', data)
.success(function (result) {
//Handle success
})
.error(function (err) {
//Handle error
});
This route is handled within NodeJs that then does the actual POST. Upon success, within the route handler, I redirect:
function handlePostRequest (req, res) {
//Route handler
//HTTP POST Request
//Following code called when POST request is successful
if (result) {
//Successful post
res.redirect("http://www.google.com");
}
}
However, the browser does not navigate to google. Instead, in the error handler of the POST request within the AngularJS client, the control is reached.
I checked the server and find that the POST request is returned as status code 302 and thus is picked by the error handler for the POST request in the client.
I cannot figure out why, when the server successfully executes the redirect code, the control still reaches the client and that too the error handler. How do I redirect successfully?
Is it a HTTP POST in angular or an XHR? If it's an XHR you can't redirect the client from serverside, you'd need to send back an error which you then handle in your clientside script such as:
$http({
method: 'POST',
url: 'yoururl',
}).success(function(data, status, headers, config) {
// success stuff
}).error(function(data, status, headers, config) {
if (status == 302) {
window.location = headers('Location');
}
})
Successful XHRs come back with a status of 200. Your server handing back a 302 is technically correct, but it isn't what $http in Angular is expecting. If your server can hand you a 200, you can then do your redirect in the .success function of the $http request.
Related
Here's the code:
proxy.web(
req,
res,
{ changeOrigin: false, target: 'http://' + gotDomain.ip + ':' + gotDomain.port },
function (error, req, res) => {
console.log('Error')
res.end('Error')
}
)
If I stop the target server, the console log fires.
The response res.end('Error') does not work.
The request just hangs on the client side. I can run any code I want in the error callback and I can see the res variable is an http response object. I've tried adding:
res.writeHead(500, {
'Content-Type': 'text/plain'
});
I've tried using the proxy.on('error'... setup and the results are exactly the same:
The callback runs
The res variable is a valid http response object
Whatever I put in res.end() doesn't get sent to the client
The client hangs forever waiting for a response.
I've checked this answer:
Node.js http-proxy: Error response not sent to client
I'm not sure how that solution could work because my proxy response doesn't have status() or send() methods. I get TypeError: res.status is not a function if I try those.
With http-proxy, I use end() whenever I'm returning a response.
I am fairly new to Node-Express. I am using the Express Router for routing the request. What I am basically doing is a video view, then delete function.
This is my code.
router.get('/videodelete', function(req, res) {
// Some synchronous operation using sync-exec
res.writeHead(200, {
"Content-Type": "text/html"
});
res.end('<video src="../video/video.mp4" controls></video>');
// response is sent. Now delete the file after the response is shown.
fs.unlink("../video/video.mp4");
})
I also tried fs.unlinkSync. In all these cases, the delete operation is happening before sending the response. I wish to trigger the delete operation only after sending response. Is there any way to perform this action only after sending the response?
Im doing a node app, which has a html form doing an action to /users
This url calls this method on post
exports.create = function(req, res, next) {
const user = new User(req.body);
user.save((err) => {
if (err) {
return next(err);
} else {
res.status(302).json(user).redirect('/chat');
}
});
};
However i'm unable to do a redirect after storing the data in my db, and get the error Can't set headers after they are sent.
I've tried placing the redirect different places in the form, but i keep getting the same error.
Try removing .json(user) from the redirect. You cannot both send a JSON and a redirect at the same time.
Or if you want to send the JSON, maybe as a response to an Ajax request, don't send .status(302) but do the redirect on client side JavaScript.
Node.js (express) web server
Request handler in web server
app.get('/documents/ajax/:id.:format?', function(req, res) {
console.log ('Request Received');
var body = 'hello world';
res.writeHead(200, {
'Content-Length': body.length,
'Content-Type': 'text/plain'
});
})
ajax request from client side javascript
$.ajax({
url : "/documents/ajax/" + item,
success : function(msg) {
alert ("success" + msg);
},
error : function(request, status, error) {
alert("Error, returned: " + request);
alert("Error, returned: " + status);
alert("Error, returned: " + error);
}
});
I am able to receive the request on server side and I send 4 requests
But my success event is not getting called in client side JS. Also, when I stop my web server, then I see my error handlers get called.
Please help.
The main issue is that you are not ending the response so the server never actually sends anything to the client. The server should respond with something like a file, a redirect, some text, etc. You need to finish the callback with a res.end, res.send, res.sendfile, res.redirect, res.render... See the docs.
Furthermore, with express you want to use res.set to set the http headers:
app.get('/documents/ajax/:id.:format?', function(req, res) {
console.log ('Request Received');
var body = 'hello world';
res.set({'Content-Type': 'text/plain'});
res.send(body);
});
200 is the default response code, so you don't need to specify that and the length will be computed for you. These things are often easier to debug from the command line via curl:
curl http://localhost:3000/documents/ajax/1
and
curl -I http://localhost:3000/documents/ajax/1
I had to res.end in server request handler. After that I was able to generate success event in client side JS
I have a route that redirects upon successful login
app.post('/login', function(req, res){
if(req.body.password === Server.cfg.auth.userPass) {
req.session.user = {nick: req.body.username, pass: req.body.password}
res.redirect('/chat')
} else {
res.render('user/login', { locals: { error: 'Invalid password' } })
}
})
The redirect seems to work as the page is refreshed with the correctly rendered jade file. However, the url still says /login and my pageTitle variable (being set through template vars) does not change either. If I refresh the page after the redirect, everything changes to the way it should be. It is only after the redirect that it does not change.
This has got to be a pretty common mix up for folks trying to deal with ajax redirects coming from a server controlled development background. My example shows what happens if authorization fails, slightly different; but you can use the same concept of intercepting the response and checking status, etc., and let the client JavaScript do the redirect.
My client code is actually a backbone model but in turn is calling jquery's ajax like:
model.save({ error:function...
Server
function requiresLogin(req, res, next) {
if(req.session.user) {
next();
} else {
//res.redirect('/sessions/new?redir=' + req.url); // won't work
res.send("Unauthorized", 403); // send 403 http status
}
}
Client
// Assumes you can get http status from response
error: function(resp, status, xhr)...
if(resp.status === 403) {
window.location = '/sessions/new'; // optionally put a redirLastPage=somewhere
}
This works as desired for me. I'd also suggest googling ajax post redirects to see why this
Looks like this is a jQuery problem. At least it was for me. You can override it with rel=external. More info at http://jquerymobile.com/demos/1.1.0/docs/pages/page-navmodel.html.