Search code examples
javascriptmysqlnode.jsexpresspug

Node Express MySQL and the Error: Can't set headers after they are sent


I am working with Node.js, Express.js, and a MySQL database. Within the database I have posts that I would like to display using Pug.js view engine. I got it to work by connecting to the database and rendering the home route correctly but I am apparently making a second callback because I get the Error:

Can't set headers after they are sent.

I am unsure of how to fix this without breaking it further because it actually renders as expected now. Here is what I am working with:

app.js:

// Home Route
app.get('/', function(req, res){

  //get posts from database to show on news section.
  var postList =  [];

  db.query('SELECT * from articles', function(err, rows) {

    if(err) throw err;
    for (var i = 0; i < rows.length; i++) {
      //missing the img fields
      var post = {
        'id':rows[i].id,
        'title':rows[i].title,
      }
      //Add the newly created post object to the postList array
      postList.push(post);

      //THE ERROR IS PROBABLY BECAUSE OF THIS \/

      res.render('index', {
        title:'mySite',
        page: 'News',
        postList: postList});
    }
  });
});

here is the index.pug:

extends layout

block content
  table
    for post in postList
      tr
        td
          h3 #{post.title}
        td
          p #{post.id}

Once again it renders fine but the terminal is throwing the error at me and i would prefer to fix it if possible. I have tried to pull the res.render for the index out of the query like this:

// Home Route
app.get('/', function(req, res){

  //get posts from database to show on news section.
  var postList =  [];

  db.query('SELECT * from articles', function(err, rows) {

    if(err) throw err;
    for (var i = 0; i < rows.length; i++) {
      //missing the img fields
      var post = {
        'id':rows[i].id,
        'title':rows[i].title,
      }
      //Add the newly created post object to the postList array
      postList.push(post);

    }
  });
      //THIS FIXES THE ERROR \/

      res.render('index', {
        title:'mySite',
        page: 'News',
        postList: postList});
      //THIS NO LONGER RENDERS THE postList ARRAY
});

Any help with this would be appreciated. Thanks.


Solution

  • You almost made it right, man! but the render should be inside db.query such as

    //get posts from database to show on news section.
      var postList = [];
    
      db.query('SELECT * from articles', function (err, rows) {
    
        if (err) throw err;
        for (var i = 0; i < rows.length; i++) {
          //missing the img fields
          var post = {
            'id': rows[i].id,
            'title': rows[i].title,
          }
          //Add the newly created post object to the postList array
          postList.push(post);
    
        } // end for loop
    
        res.render('index', {
          title: 'mySite',
          page: 'News',
          postList: postList
        });
      });
    

    The explanation is db.query is callback function, if you put res.render outside it, javascript engine will execute it first so you will get nothing in your postList. So, you must wait until db.query finish and populate your postList then render it.

    Why you got Can't set headers after they are sent because you execute res.render multiple times (you put it inside the loop). It must be executed just once.

    Hope it helps.