Search code examples
javascriptnode.jsexpressfetch

How to fix err_http_headers_sent


I tried fix an error: [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client but I haven't idea how to do it. I've tried many possibilities, but they haven't worked, or I have wrong used that solutions.

  • server.js
const express = require('express')
const mysql = require('mysql')
const cors = require('cors')
const app = express()

const parser = express.urlencoded({extended:false})
app.use(cors())
app.set('view engine', 'ejs')
app.use(express.static('public'));

const con = mysql.createConnection({
    host: "localhost",
    user: "root",
    password: "",
    database: "expenseapp"
})
con.connect(err=>{
    if(err)
        throw err;
    console.log('connected!');
    
})

let array = [] 

app.get('/',(req,res)=>{
    res.render('index')
    let queryName = "SELECT * from `expenses`";
    con.query(queryName, (err,res)=>{
        if(err)
            throw err
        res.forEach(element => {
            array.push(element)
        });
    })
    res.json(array)
    
})
app.get('/add', (req,res)=>{
    res.render('add')
})
app.post('/add', parser, (req,res)=>{
    let array = [req.body.product, req.body.cost]
    let sqlquery = "INSERT INTO `expenses` (name, cost) VALUES (?)";
    con.query(sqlquery, [array], (err,res)=>{
        if(err)
            throw err
        console.log("saved new product");
    })
    res.render('add')
})

app.listen(PORT, ()=>console.log(`Server's running on PORT ${PORT}`))
  • app.js
    .then(response => {return response.json()})
    .then(data => console.log(data))
    .catch(err => console.log(err))

directory order:

node_modules
public:
___javascripts
   ___app.js
___styles
   ___style.css
views:
___add.ejs
___index.ejs
package-lock.json
package.json
server.js

Give me answer how to fix that trouble please. Thanks :)


Solution

  • This request handler:

    app.get('/',(req,res)=>{
        res.render('index')
        let queryName = "SELECT * from `expenses`";
        con.query(queryName, (err,res)=>{
            if(err)
                throw err
            res.forEach(element => {
                array.push(element)
            });
        })
        res.json(array)
        
    })
    

    is calling both res.render() and res.json(). Each of those tries to send a response to the request and the second one will trigger the error you report because you only get to send one response per request. It's not clear exactly what you want this route to be. If you want to pass the query results to the template, then you would do something like this:

    app.get('/',(req,res)=>{
        const queryName = "SELECT * from `expenses`";
        con.query(queryName, (err,res)=>{
            if (err) {
                console.log(err);
                res.sendStatus(500);
                return;
            }
            res.render('index', res);   // if res isn't already an array, convert it to an array
        });
    });
    

    Note, several things being done differently here:

    1. Add error handling on the query that logs the error and sends an actual error response. throw err will not be useful here.
    2. Remove res.json() so we're only sending one response instead of two.
    3. Call res.render() with your template and pass it the array of results so the template index can use that data in generating the page.
    4. Move the res.render() inside the database callback where we actually have the data available.

    If you intend for this route to accomplish something different than I've coded it for here, then please describe what this route is supposed to do.

    FYI, you should not be using if(err) throw err; in any asynchronous callback. It's not doing you any good as none of your code can actually catch any of those asynchronously thrown exceptions and do something intelligent with them. You need real error handling in all your asynchronous operations. Don't skip that step when writing code. Don't leave it for later. Think about error handling as a primary concept when designing and first writing your code.