Redirect after already used response Node js - javascript

I want to render some page and after certain amount of seconds it needs to be redirected to another page. However, I get an "Can't set headers after they are sent." From what I read, the response should be used only once, though I'm not sure if this is true. I would appreciate any help or solution to this particular problem.
app.get('/', function (req, res) {
var message = req.flash();
res.render('index', { message: req.flash('message'), hassError: message.length > 0} );
});
app.get('/error', function (req, res) {
var timeout = 3000;
setTimeout(function (err) {
console.log('finished');
if (err)
throw err;
console.log('################');
res.redirect('/');
}, timeout);
res.render('partials/404');
});
"finished" gets printed and then it throws error, but not the err specified in callback.

You can't use this approach - rendering means sent to browser with headers, then the HTTP request is closed by browser. You can't send a second response.
You'll have to do the timeout logic in JavaScript on the page, not server:
<script>
var timeout = 3000;
setTimeout(function () {
window.location = "http://www.yoururl.com";
}, timeout);
</script>

You can't send multiple responses to a single request. It's like if someone asks you for a burger, you give them a burger, and they walk away. Some time later you lob another burger at the back of their head. They aren't going to catch it.
In this case, you'll need to handle redirecting on the client-side. If this is just a regular page render, you can use the refresh attribute of a meta tag.
<meta http-equiv="refresh" content="2; url=http://path/to/my/page/" />
If this is an AJAX request, you'll need to have the client perform the redirect after a delay.

The redirect you are trying to send should be done either on the server side right when the user hits the server, or done on the browser after the 404 page has loaded.

Related

I don't fully understand what app.get('/consult')

I am new to express and I still struggle with the meaning of app.get().
In my HTML page, I have a button with the id=consult-button.
I gave it the following script:
document.getElementById("consult-button").addEventListener("click", function() {
window.location.href = '/consulting';
});
On my app.js file, on the other hand, I have:
app.get('/consulting', (req, res) => {
const client = new pg.Client(config);
client.connect();
client.query('SELECT * FROM questionaire', (err, result) => {
if (err) {
console.log(err);
}
res.send(result.rows);
client.end();
});
});
Can someone help me understand this? Tell me if what I am writing is right:
when the button is clicked, a url with the name "consulting" is created. then app.get call on that url and sends the results of the query in that url?
When the user clicks on the button on the web page, the browser is going to send an HTTP GET request to the endpoint on the server (/consulting),
for example, if your website domain is www.example.com, the browser is going to send the request to www.example.com/consulting,
or if your domain is 192.168.1.50:3000 for example in case you're working on localhost for example, the website is going to send a request to 192.168.1.50:3000/consulting.
But this piece of code doesn't only send a request to the server, it also changes the URL to /consulting, (ex: www.example.com becomes www.example.com/consulting).
Now when the request travels from the website (the computer of the website visitor) to the back-end server (which is express in your case), express is going to catch this request in the following controller (it's called a controller)
app.get('/consulting', (req, res) => {
const client = new pg.Client(config);
client.connect();
client.query('SELECT * FROM questionaire', (err, result) => {
if (err) {
console.log(err);
}
res.send(result.rows);
client.end();
});
});
app.get is the controller which catches this request and handles it because it's
app.get('/consulting') which matches the destination of the request.
Now this controller has a bunch of codes, it basically sends a request to the Postgres database saying "SELECT * FROM questionaire" which basically means give me all the entries inside the questionaire table.
the database responds with that, so the server (the controller) takes care of the response from the database and forwards it back to the website.
Hope this helps.

Why is "module.exports = (req, res) => {" stopping my routing from working

A href is called like so:
<a class="navlink" href="/auth/logout">Logout</a>
When clicked a controller in the middleware(named "auth.js"), and another controller "logout.js" is called , it doesn't do anything. The session should destroy and redirect the index. Instead the pay flinches slightly but stays on the current page.
"auth.js"
const User = require('../database/models/User')
module.exports = (req, res, next) => {
User.findById(req.session.userId, (error, user) => {
if (error || !user) {
return res.redirect('create')
}
next()
})
}
logout.js"
module.exports = (req, res) => {
req.session.destroy(() => {
res.redirect('/')
})
}
I expect the controller to direct to the index.
If the button is ultimately triggering an ajax call through the controller to your server, then ajax calls don't by themselves pay any attention to redirect responses (so thus the res.redirect() does nothing). You would have to have code in the client-side controller that sees that redirect response from the ajax call and then acts on it by setting window.location accordingly to cause the browser page to change.
Things in the browser that do automatically follow a redirect in the response:
Type a URL in the URL bar of the browser
Following a link in a web page (such as Click here)
Setting window.location via Javascript
The response from a form post (submitted automatically by the browser, not via Javascript)
So, if your request is being sent via Javascript, then it won't automatically follow a redirect response. Your Javascript would have to see the response come back, see that it's a 3xx response, fetch the redirect location from the response and then set window.location to tell the browser to go to that new location.

Sending information to server and getting processed data back using nodejs

I'm trying to make an application using nodejs, express and ejs. What I'm aiming to do is submitting a form to the server, trigger a server function which processes the data to get some result, and getting my page to display the result without reloading the whole page.
Currently this is what I have:
ejs
<form method = "GET" action = "/sendinput"
...something here
</form>
app.js
app.get('/sendinput', function (req, res) {
result = processData(req.query);
});
I manage to get the function to run when the form is submitted, but after that the page keeps loading even after the function finishes running. I'm also not sure how to fetch the result and let the form segment of the html displays it without reloading the whole page.
To stop the page from loading, use res.end();
it will signal the server that your function is done.
app.get('/sendinput', function (req, res) {
result = processData(req.query);
res.end();
});
So in the end I solve it by using Ajax, which doesn't prompt the page for a reload and manage to get what I want.

Why does settimeout break Expressjs

I have the following code in express.js
// POST api/posts/:id
exports.post = function(req, res){
req.body[0].id = posts.length + 1;
posts.push(req.body[0]);
console.log(posts);
fs.writeFileSync("json/posts.json", JSON.stringify(posts));
setTimeout(function(){
res.set.apply(res, utils.contentType);
res.json(req.body[0]);
}, utils.randomNumberBetween(1000, 3000));
};
When I post a simple json object I receive the following error.
org.apache.http.NoHttpResponseException: localhost:9000 failed to respond
If I remove the settimeout everything works as expected. I have used settimeout in other places like so:
// GET api/posts
exports.get = function(req, res){
setTimeout(function(){
res.set.apply(res, utils.contentType);
res.json(posts);
}, utils.randomNumberBetween(1000, 3000));
};
So I'm not understanding why it would break when posting. Any thoughts??
This is because the application making the request expects a response from express within a certain amount of time, say 5 seconds. If it does not receive anything back it thinks something went wrong. One thing you can do to resolve this is change the amount of time your "sending/requesting" application waits/listens for a response.

Passing error message to template through redirect in Express/Node.js

In my Node.js application, I have a function (routed by Express) which presents a form to the user:
app.get('/register', function (req, res) {
res.render('form');
});
I have another function, routed to the same URL, but which handles POST requests, which receives the data submitted by the previous form. If the form does not validate, it redirects the user back to the form; otherwise, it does what should be done:
app.post('/register', function (req, res) {
if (validate(req.registerForm)) return res.redirect('back');
persistStuff(req.registerForm, function (err, data) {
// Do error verification etc.
res.redirect('back')
});
});
What I want to do is to send a error message to be presented, in the line:
if (validate(req.registerForm)) return res.redirect('back');
To write something like
if (validate(req.registerForm)) return res.render('form', {msg:'invalid'});
is unacceptable because I want to follow the POST-REDIRECT-GET pattern. I could do something like
if (validate(req.registerForm)) return res.redirect('/register?msg=invalid');
but it would hardcode an URL in my code and I'd prefer to avoid it. Is there another way to do it?
You need to use flash notifications, and it is built into express.
You'll add a message like so: req.flash("error", "Invalid form...");
You'll need a dynamic handler to add the messages to your rendered template, or you can check out the ones TJ has made for express. (express-messages)
You could simply have it redirect as res.redirect('..?error=1')
the ? tag tells the browser that it is a set of optional parameters and the .. is just a pathname relative recall (like calling cd .. on terminal to move back one directory)
and you're browser will direct to the appropriate page with that tag at the end: http://.....?error=1
then you can simply pull the error on the appropriate page by doing a:
if (req.param("error" == 1)) {
// do stuff bassed off that error match
};
you can hardcode in several different error values and have it respond appropriately depending on what error occurred

Categories

Resources