Home > Back-end >  error of cannot set headers after they are sent to the client though i am returning response
error of cannot set headers after they are sent to the client though i am returning response

Time:01-04

I am working on expressJS and this is my code in route:

router.route("/")
    .post(upload, RecordController.post_record);

and this is the post_record function:

const fs = require("fs");
const readLine = require("readline");


exports.post_record = (req, res) => {

    //it's not actually needed but i am doing this just for sake of checking
    if (!req.file) {
        return res.status(422).json({
            message: 'The file is required.'
        });
    }

    //checking if file is empty
    if (req.file.size == 0) {
        return res.status(400).send("file is empty");
    }

    try {
        // result storing object
        const results = {
            P: 0,
            QRS: 0,
            meanFrequency: 0,
            minFrequency: {
                value: 9999999,
                time: 0
            },
            maxFrequency: {
                value: 0,
                time: 0
            }
        };

        //for mean frequency calculation
        const frequencyCollector = {
            sumOfFrequency: 0,
            cycleCount: 0
        };

        //entries of valid wave type object to check if the wave type in our csv are valid data-sets
        const expectedWave = {
            P: true,
            QRS: true,
            T: true,
            INV: true
        };

        let time = 0;
        let lastTimeStamp = 0;

        readLine.createInterface({
            input: fs.createReadStream(req.file.path)
        }).on("line", line => {
            const cols = line.split(",");
            const waveType = cols[0];
            const startTime = cols[1];
            const endTime = cols[2];
            const tags = cols.slice(3);

            //just to make sure csv has valid data list
            if (!(waveType in expectedWave && Number(startTime) >= 0 && Number(endTime) > 0)) {
                res.status(500).send("File data entry is not in supported format");
                return;
            }

            else{
                if ((waveType === "P" || waveType === "QRS") && tags.includes("premature")) {
                    results[waveType]  ;
                }

                time  = (cols[2] - cols[1]);
                time  = (cols[1] - lastTimeStamp);
                lastTimeStamp = cols[2];

                if (waveType === "QRS") {
                    let frequency = Math.floor((60 / time) * 1000);

                    //check if frequency is maxValue or minValue
                    if (frequency > results.maxFrequency.value) {
                        results.maxFrequency.value = frequency;
                        results.maxFrequency.time = Number(cols[2]);
                    }

                    if (frequency < results.minFrequency.value) {
                        results.minFrequency.value = frequency;
                        results.minFrequency.time = Number(cols[2]);
                    }

                    frequencyCollector.sumOfFrequency  = frequency;
                    frequencyCollector.cycleCount  ;
                    time = 0;
                }
            }


        }).on("error", (err) => {
            return res.status(500).send(`error is: ${err.message}`);
        }).on("close", () => {
            let heartRate = Math.floor(frequencyCollector.sumOfFrequency / frequencyCollector.cycleCount);
            results.meanFrequency = heartRate;
            results.maxFrequency.time  = Number(req.body.time);
            results.minFrequency.time  = Number(req.body.time);
            res.status(200).json(results);
            return;
        });

    } catch (err) {
        console.error(err);
        res.status(500).send(`there is an error with message: ${err.message}`);
        return;
    }
}

and moreOver, this is my main_server file mean where I listen the port:

app.use(bodyParser.json());

//setting the statics
app.use(express.static(path.join(__dirname, "./public/")));


//use record.js file to handle the requests that starts with /things
//settingup the delineation route
app.use("/POST/delineation", recordRoute);

app.get("/", (req, res)=>{
    //determine the content-type and automatically set header for us, awesome !!!
    res.sendFile(path.join(__dirname, "/index.html"));    
});

app.use((req, res, next)=>{
   return res.status(404).send("Page not found");
});

//for error handling; error handling middleware
app.use((err, req, res, next)=>{
   return res.status(500).send(`Sorry there is error with message saying: ${err.message}`);
})

app.listen(3000, (err)=>{
    if(err){
        console.log(`there is error - ${err}`);
    }
    console.log("listening on port 3000");
});

my problem is that whenever i upload a file on the this post route with file that satisfy the error condition of

  if (!(waveType in expectedWave && Number(startTime) >= 0 && Number(endTime) > 0)) {
                res.status(500).send("File data entry is not in supported format");
                return;
            }

in the controller code above server give this error:

http_outgoing.js:558 throw new ERR_HTTP_HEADERS_SENT('set'); ^ Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

CodePudding user response:

I think in your readLine handlers when you return in its functions, it just return from those function. try with a return in behind of readLine.createInterface

CodePudding user response:

The problem is that the stream is still sending the response multiple times from line event, every time it reads a line.

So, you need to end the stream.

However, it doesn't seem to work like that, because:

Calling rl.close() does not immediately stop other events (including 'line') from being emitted by the InterfaceConstructor instance.

https://nodejs.org/api/readline.html#rlclose

which means the line will emit again, and cause the same error, so you cannot return response from the line event, but somewhere else.

You need to rewrite the code accordingly.

For example, add the variable to track the error manually, close the stream in line, and then check for error there, and return error, if any, success if not.

// track error
let error;

// setup reader to close it later
const reader = readLine.createInterface({

//...

if (!(waveType in expectedWave && Number(startTime) >= 0 && Number(endTime) > 0)) {
    error = 'File data entry is not in supported format';
    // close
    reader.close()
    return;
}

//...

}).on("close", () => {
            if (error) {
                res.status(500).send(error);
                error = '';
                return;
            }
//...           
  •  Tags:  
  • Related