Anwesa Roy
Anwesa Roy

Reputation: 33

Error in nodejs : Cannot set headers after they are sent to the client

I am creating a simple form using HTML and nodejs. The form takes in two data namely email and password and works according to the functionality written in the code.

I have two files app.js and index.html in my program.

app.js

const _ = require('lodash');
const express = require('express');
const path = require('path');
const Joi = require('joi');
const bodyParser = require('body-parser');
const app = express();

app.use(bodyParser.urlencoded({extended:false}));
app.use(bodyParser.json());

app.get('/',(req,res)=>{

    res.sendFile(path.join(__dirname,'index.html'));

});

app.get('/example',(req,res)=>{

    res.send('Hitting Example Route');

});

app.get('/example/:name/:age',(req,res)=>{

    console.log(req.params);
    console.log(req.query);
    //res.send('example with route params');
    res.send(req.params.name+":"+req.params.age);

});

app.post('/',(req,res)=> {
    console.log(req.body);
    const schema = Joi.object().keys({

        email : Joi.string().trim().email().required(),
        password : Joi.string().min(5).max(10).required()
    });

    Joi.validate(req.body,schema,(err,result)=>{
        if(err)
        {
            console.log(err);
            res.send('An error has occured');
        }
        console.log(result);
        res.send('Successfully posted data');

    });
    //database work here

    //res.json({success:true});

});

app.listen(3000);

index.html

<!DOCTYPE html>
<html>

   <head>
      <title>Text Input Control</title>
   </head>

   <body>
      <!--<form !action="/"></form> method="POST" id="form">-->
      <form  method="POST" id="form">

         First name: <input type = "text" name = "first_name" />
         <br>
         Last name: <input type = "text" name = "last_name" />

         <input type="submit" value="Submit">

      </form>

            <script
        src="http://code.jquery.com/jquery-3.3.1.js"
        integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60="
        crossorigin="anonymous"></script>

        <script>
            $(document).ready(()=>{
                $('#form').submit((e)=>{
                    e.preventDefault({});
                    $.ajax({

                        url : '/',
                        type : 'post',
                        contentType : 'application/json',
                        data : JSON.stringify($('#form').serializeArray()),
                        success : (response)=>{

                            console.log('Successfuly got response');
                            console.log(response);

                        }

                    });

                });


            });

        </script>

   </body>

</html>

I get an error stating Cannot set headers after they are sent to the client. How may I fix the code?

Error:

PS F:\DatabaseProject8> node app.js
[ { name: 'first_name', value: '[email protected]' },
  { name: 'last_name', value: 'gredyjht' } ]
{ ValidationError: "value" must be an object
    at Object.exports.process (F:\DatabaseProject8\node_modules\joi\lib\errors.js:203:19)
    at internals.Object._validateWithOptions (F:\DatabaseProject8\node_modules\joi\lib\types\any\index.js:764:31)
    at module.exports.internals.Any.root.validate (F:\DatabaseProject8\node_modules\joi\lib\index.js:147:23)
    at app.post (F:\DatabaseProject8\app.js:40:9)
    at Layer.handle [as handle_request] (F:\DatabaseProject8\node_modules\express\lib\router\layer.js:95:5)
    at next (F:\DatabaseProject8\node_modules\express\lib\router\route.js:137:13)
    at Route.dispatch (F:\DatabaseProject8\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (F:\DatabaseProject8\node_modules\express\lib\router\layer.js:95:5)
    at F:\DatabaseProject8\node_modules\express\lib\router\index.js:281:22
    at Function.process_params (F:\DatabaseProject8\node_modules\express\lib\router\index.js:335:12)
  isJoi: true,
  name: 'ValidationError',
  details:
   [ { message: '"value" must be an object',
       path: [],
       type: 'object.base',
       context: [Object] } ],
  _object:
   [ { name: 'first_name', value: '[email protected]' },
     { name: 'last_name', value: 'gredyjht' } ],
  annotate: [Function] }
[ { name: 'first_name', value: '[email protected]' },
  { name: 'last_name', value: 'gredyjht' } ]
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:470:11)
    at ServerResponse.header (F:\DatabaseProject8\node_modules\express\lib\response.js:767:10)
    at ServerResponse.send (F:\DatabaseProject8\node_modules\express\lib\response.js:170:12)
    at Joi.validate (F:\DatabaseProject8\app.js:47:13)
    at internals.Object._validateWithOptions (F:\DatabaseProject8\node_modules\joi\lib\types\any\index.js:767:20)
    at module.exports.internals.Any.root.validate (F:\DatabaseProject8\node_modules\joi\lib\index.js:147:23)
    at app.post (F:\DatabaseProject8\app.js:40:9)
    at Layer.handle [as handle_request] (F:\DatabaseProject8\node_modules\express\lib\router\layer.js:95:5)
    at next (F:\DatabaseProject8\node_modules\express\lib\router\route.js:137:13)
    at Route.dispatch (F:\DatabaseProject8\node_modules\express\lib\router\route.js:112:3)

Upvotes: 0

Views: 389

Answers (4)

Sumit Kumar
Sumit Kumar

Reputation: 823

The error you got is because of the asynchronous nature of Nodejs. Use Promise/Async-Await to prevent this type of error. Using Async-Await

app.post('/',async(req,res)=> {
console.log(req.body);
const schema = Joi.object().keys({

    email : Joi.string().trim().email().required(),
    password : Joi.string().min(5).max(10).required()
});

let result = await Joi.validate(req.body,schema);
if(result.err){
    console.log(err);
    res.send('An error has occured');
}else{
    console.log(result);
    res.send('Successfully posted data');
}
//database work here

//res.json({success:true});

});

This may do the job

Upvotes: 0

Sergi Nadal
Sergi Nadal

Reputation: 960

I had this problem sometimes, I solved changin res.send for res.redirect('/example').

Another thing you can try is change the if statement, is it possible in case of an error res.send is executed 2 times:

if(err){
            console.log(err);
            res.send('An error has occured');
        } 
else {
        console.log(result);
        res.send('Successfully posted data'); 
}

Upvotes: 0

Vinil Prabhu
Vinil Prabhu

Reputation: 1289

the schema you defined might be incorrect

define it like this

const schema = {
    email: Joi.string().trim().email().required(),
    password: Joi.string().min(5).max(10).required()
};

Upvotes: 0

Mohammad
Mohammad

Reputation: 1990

The reason you are getting an error about setting headers twice, is that an error is happening in Joi.validate callback. You are sending "An error has occured" but then after the error handler you are still sending as well "Successfully posted data". You shouldn't call send twice otherwise you will get that error. You should exit the Joi.validate callback when an error occurs.

Upvotes: 2

Related Questions