Api headers error with nodejs

Asked

Viewed 197 times

-1

[nodemon] restarting due to changes...
[nodemon] starting `node index.js`
rodando na porta 3000, Ctrl+C para parar
/Users/jeffersonrodrigues/Dev/nodeProjects/minhaescola_api/node_modules/mysql/lib/protocol/Parser.js:437
      throw err; // Rethrow non-MySQL errors
      ^

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:526:11)
    at Query.<anonymous> (/Users/jeffersonrodrigues/Dev/nodeProjects/minhaescola_api/routes/user/login.js:24:13)
    at Query.<anonymous> (/Users/jeffersonrodrigues/Dev/nodeProjects/minhaescola_api/node_modules/mysql/lib/Connection.js:526:10)
    at Query._callback (/Users/jeffersonrodrigues/Dev/nodeProjects/minhaescola_api/node_modules/mysql/lib/Connection.js:488:16)
    at Query.Sequence.end (/Users/jeffersonrodrigues/Dev/nodeProjects/minhaescola_api/node_modules/mysql/lib/protocol/sequences/Sequence.js:83:24)
    at Query._handleFinalResultPacket (/Users/jeffersonrodrigues/Dev/nodeProjects/minhaescola_api/node_modules/mysql/lib/protocol/sequences/Query.js:149:8)
    at Query.EofPacket (/Users/jeffersonrodrigues/Dev/nodeProjects/minhaescola_api/node_modules/mysql/lib/protocol/sequences/Query.js:133:8)
    at Protocol._parsePacket (/Users/jeffersonrodrigues/Dev/nodeProjects/minhaescola_api/node_modules/mysql/lib/protocol/Protocol.js:291:23)
    at Parser._parsePacket (/Users/jeffersonrodrigues/Dev/nodeProjects/minhaescola_api/node_modules/mysql/lib/protocol/Parser.js:433:10)
    at Parser.write (/Users/jeffersonrodrigues/Dev/nodeProjects/minhaescola_api/node_modules/mysql/lib/protocol/Parser.js:43:10) {
  code: 'ERR_HTTP_HEADERS_SENT'
}
[nodemon] app crashed - waiting for file changes before starting...

Here’s my API code:

require('dotenv-safe').config();

const express = require('express');
const jwt = require('jsonwebtoken');
const db = require('../../model/bd');

//config express
const router = express.Router();

router.post('/', (req, res) => {
    var matricula = req.body.matricula;
    var senha = req.body.senha;

    db.query(`select * from aluno where mat_aluno='${matricula}' and senha='${senha}' `, (error, results) => {
        if (error || results.lenght === 0) {
            res.status(401).json({
                message: 'Falha na autenticacao',
            });
        }
        const token = jwt.sign({ 
            id_aluno : results[0].mat_aluno 
        },
        process.env.SECRET, { expiresIn: '1h' });
        res.setHeader({'Content-Type': 'application/json'})
        res.status(200)
            .json({
                message: 'Autenticado',
                token,    
                data: results
            }
        );
        return;
    });
    res.status(404).json({
       message: 'Usuario nao encontrado',
    });
    return;
});

module.exports = router;

1 answer

0

The problem is that you are always running the following code:

res.status(404).json({
  message: 'Usuario nao encontrado'
});

It defines the status of the answer as 404 and a response in JSON, which also ends up defining the header reply Content-Type as application/json. After that, the callback of query the database is running, which will again be sending a reply to the customer:

res.status(401).json({
  message: 'Falha na autenticacao'
});

// OU:

res.status(200).json({
  message: 'Autenticado',
  token,    
  data: results
});

This causes errors since it is not allowed to send other headers after the body of the response has been started. From the way your code was structured, the following is happening:

  1. Send status 404, header Content-Type and initiate the body of response.
  2. Send status 401 or 200, header Content-Type and some other body part. That is incorrect. As said above, no headers are sent after the body has been started.

It’s important to keep nature in mind asynchronous Javascript. Your code evidently doesn’t take this into account.

To fix it, you must put all the answers within of callback, or restructure its code. In the latter case, async/await may be an option.

Keeping the callbacks, you can do it:

router.post('/', (req, res) => {
  const matricula = req.body.matricula;
  const senha = req.body.senha;

  // prettier-ignore
  db.query(`select * from aluno where mat_aluno='${matricula}' and senha='${senha}' `, (error, results) => {
    if (error || results.lenght === 0) {
      res.status(401).json({
        message: 'Falha na autenticacao'
      });
    }

    const token = jwt.sign(
      { id_aluno: results[0].mat_aluno },
      process.env.SECRET,
      { expiresIn: '1h' }
    );

    res.status(200).json({
      message: 'Autenticado',
      token,
      data: results
    });
  });
});

Note that now all customer responses are within the callback, which will ensure that the reply is only sent after the result (or error) of the query.

I also removed this line of code:

res.setHeader({ 'Content-Type': 'application/json' });

It is unnecessary, since res.json already sets this header for you.


As a last note, it is important to say that your query is extremely susceptible to severe vulnerability, Injection of SQL. To learn more, read here.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.