I'm learning node Js and i'm trying to do a simple subscribe/log_in app. I'm having issue with res.json not working as intended.
Got this error when i'm trying to subscribe : Can't set headers after they are sent
This is my server side script :
var express = require('express'); var swig = require('swig'); var ent = require('ent'); var bodyParser = require('body-parser'); var mongoose = require('mongoose'); var session = require('express-session'); var app = express(); // Environnement app.set('port', process.env.PORT || 3000); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.use("/public", express.static(__dirname + "/public")); app.engine('html', swig.renderFile); app.set('view engine', 'html'); app.set('views', __dirname + '/views'); app.set('view cache', false); swig.setDefaults({ cache: false }); app.use(session({ secret: 'poussixthetruefighteroftheparadise', saveUninitialized: true, resave: true })); //MongoDB var db = mongoose.connect('mongodb://127.0.0.1:27017/maBase'); var userSchema = new mongoose.Schema({ login: String, mail: String, password: String }); var user = db.model('user', userSchema) // variables globales var state; // Page Principale app.get('/', function(req,res){ if (req.session.user) { res.render('accueil.html',{}); } else { res.redirect('/connection'); } }); // Page connection app.route('/connection') .get(function(req, res) { res.render('index.html',{}); if (req.session.state) { res.json({state: req.session.state}); } }) .post(function(req, res) { user.find({login: req.body.login, password: req.body.password}).limit(1).exec(function (err, users) { if (err) { console.log(err) }; if (!users.length) { console.log('connection pas ok'); res.json({state: '5'}); } else { console.log('connection ok'); res.redirect('/'); } }); }); // Ajouter Utilisateur app.post('/connection/ajouter', function(req,res){ var login = req.body.login; var mail = req.body.mail; user.find({$or: [{login: login}, {mail: mail}]}).limit(1).exec(function (err, users) { if (err) { console.log(err) }; if (!users.length) { console.log('login et mail ok'); if (req.body.password == req.body.password2) { if (req.body.password.length > 6) { var values = new user({ login: ent.encode(req.body.login), mail: ent.encode(req.body.mail), password: ent.encode(req.body.password) }); values.save(function(err, values) { if (err) return console.error(err); console.log('utilisateur enregistré'); req.session.state = '6'; res.redirect('/connection'); }); } else { console.log('Mot de passe trop court'); req.session.state = '3'; res.redirect('/connection'); } } else { console.log('mot de passe différent'); req.session.state = '4'; res.redirect('/connection'); } } else { console.log('login ou mail déja utilisé'); if (users[0].mail == mail) { console.log('mail déja utilisé'); req.session.state = '2'; res.redirect('/connection'); } else { console.log('login déja utilisé'); req.session.state = '1'; res.redirect('/connection'); } console.log(users); } }); }); app.listen(app.get('port'), function(){ console.log('Express server listening on port ' + app.get('port')); });
And my client side script :
<html> <head> <title>test</title> <link rel="stylesheet" href="public/css/reset.css"> <link rel="stylesheet" href="public/css/connection.css"> </head> <body> <div id="content"> <a href="http://localhost:3000"><img src="public/images/icone.jpg" alt="gatsbill"></a> <div id="wrap"> <div id="espacehaut"></div> <div class="click" id="con" style="display: block;">Se connecter</div> <div class="click" id="sub" style="display: none;">S'inscrire</div> <div id="connection" style="display: none;"> <div id="message1" class="message" style="display: none;"></div> <form action="/connection/" method="post" id="form_connection"> <input type="text" name="login" id="login" placeholder="Login" value="" required="" autofocus=""> <input type="password" name="password" id="password" placeholder="Password" required=""> <input type="submit" name="submit" value="Connect"> </form> </div> <div id="subscribe" style=""> <p id="p">Pour vous inscrire,<br> Veuillez remplir les champs ci-dessous</p> <div id="message2" class="message" style="display: none;"></div> <form action="/connection/ajouter/" method="post" id="form_inscription"> <input type="text" name="login" placeholder="Login" value="" required="" autofocus=""> <input type="email" name="mail" placeholder="Email" value="" required=""> <input type="password" name="password" placeholder="Password" required=""> <input type="password" name="password2" placeholder="Password" required=""> <input type="submit" name="submit" value="Create account"> </form> </div> <div id="espacebas"></div> </div> </div> <!-- Script --> <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script> <script type="text/javascript" src="public/js/connection.js"></script> <script> $.getJSON( "http://localhost:3000/connection", function(data){ if( data.state ) { state = parseInt(data.state); switch (state) { case 1: formulaire(); $("#message2").text("login déja utilisé"); break; case 2: formulaire(); $("#message2").text("mail déja utilisé"); break; case 3: formulaire(); $("#message2").text("Mot de passe trop court"); break; case 4: formulaire(); $("#message2").text("mot de passe différent"); break; case 5: connect(); $("#message1").text("connection pas ok"); break; case 6: connect(); $("#message1").text("vous pouvez maintenant vous connecter"); break; } } }); </script> </body> </html>
When i'm trying to subscribe with two different password this is what I have :
A white page with only this :
{"state":"4"}
And of course this error in node Js console: Can't set headers after they are sent
The error "Error: Can't set headers after they are sent." means that you're already in the Body or Finished state, but some function tried to set a header or statusCode. When you see this error, try to look for anything that tries to send a header after some of the body has already been written.
To Solve Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client Here You Need To use return statement to solve this error. Error Is occurs Because Of Your res. status(400). json is executing and then your function is not going to stop.
json() Function. The res. json() function sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a JSON string using the JSON.
send() Send a string response in a format other than JSON (XML, CSV, plain text, etc.). This method is used in the underlying implementation of most of the other terminal response methods.
Welcome to nodejs/express!
This is where you are getting your "Can't set headers after they are sent" error in the console:
// Page connection app.route('/connection') .get(function(req, res) { res.render('index.html',{}); if (req.session.state) { res.json({state: req.session.state}); } })
In this configuration, res.render
and res.json
will both call res.end()
which is basically like trying to send a response twice to the client.
You should place a return
statement before res.render
or set {state: req.session.state}
as the second param to your res.render()
call and then use a swig template to display that data.
I've solved it this way:
Override res.send in the very first middleware:
app.use(function(req,res,next){ var _send = res.send; var sent = false; res.send = function(data){ if(sent) return; _send.bind(res)(data); sent = true; }; next(); });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With