1

I am trying to build a Nodejs server that takes data from another server that contain the data then send it to the client, I am using a proxy structure to handle multiple types of connection. I am using an HTTP Express server to handle HTTP request and it works fine for the first request after the first request I have an Express error Cannot set headers after they are sent to the client

_http_outgoing.js:526
    throw new ERR_HTTP_HEADERS_SENT('set');
    ^

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the 
client
    at ServerResponse.setHeader (_http_outgoing.js:526:11)
    at ServerResponse.header (E:\Web\Projects\Color\server\node_modules\express\lib\response.js:771:10)
    at ServerResponse.send (E:\Web\Projects\Color\server\node_modules\express\lib\response.js:170:12)
    at EventEmitter.<anonymous> (E:\Web\Projects\Color\server\server.js:35:13)
    at EventEmitter.emit (events.js:323:22)
    at Socket.<anonymous> (E:\Web\Projects\Color\server\server.js:30:22)     
    at Socket.emit (events.js:323:22)
    at addChunk (_stream_readable.js:294:12)
    at readableAddChunk (_stream_readable.js:275:11)
    at Socket.Readable.push (_stream_readable.js:209:10) {
  code: 'ERR_HTTP_HEADERS_SENT'
}

My Express server code:

const express = require("express");
const net = require("net");
const http = require("http");
const login = require("./routes/auth");
const auth = require("./middlewares/verfication");
const info = require("./routes/info");
const events = require("events");
const eventEminter = new events.EventEmitter();
const app = express();

let clientSocket;

app.setClientSocket = (socket) => {
    clientSocket = socket;
    return true;
};
app.use(express.json());

app.use("/login", login);
app.use("/info", auth, info);

app.get("/", (req, res) => {
    let clientData;
    console.log("request has been made");
    clientSocket.write("GET:/");

    clientSocket.on("data", (data) => {
        clientData = data.toString();
        eventEminter.emit("ed");
        console.log(clientData);
    });

    eventEminter.on("ed", () => {
        res.send(clientData);
    });
});

module.exports = app;

The clientSocket variable represents the connection with the data server . Finally here is my server code:

const net = require("net");
const httpServer = require("./server");
//const clientServer = require("./client");
const dotenv = require("dotenv");

dotenv.config();
let clientSocket;
let registeredClient = false;

const proxyServer = net.createServer((socket) => {
    socket.on("data", (data) => {
        if (!data) {
            socket.write("Error in request");
            throw new Error("Request message is empty");
        }
        let request;
        try {
            request = data.toString();
        } catch (error) {
            console.log(
                new Error("Request message can not be conveted to String")
            );
            throw error;
        }

        if (request.includes("HTTP")) {
            const httpSocket = new net.Socket();
            if (!registeredClient) {
                registeredClient = httpServer.setClientSocket(clientSocket);
                console.log("Client registered");
            }

            httpSocket.connect(4444, () => {
                console.log("Proxy Connected to http server");
            });

            httpSocket.on("error", (err) => {
                console.error("Proxy error: Could not connect to http server");
                throw err;
            });

            const flushed = httpSocket.write(data, (err) => {
                if (err) {
                    console.error(
                        "Proxy error :Could not send data to http server"
                    );
                    throw err;
                }
            });

            // if (flushed) httpSocket.end();
            let response;

            httpSocket.on("data", (httpData) => {
                if (!httpData) {
                    console.error(
                        "Proxy error: unable to retrive data from http server"
                    );
                    return;
                }
                socket.write(httpData.toString());
            });

            // httpSocket.on("end", () => {
            //     if (!response) {
            //         console.error(
            //             "Proxy error: unable to send response or empty response message"
            //         );
            //         return;
            //     }
            //     socket.write(response);
            // });
        } else {
            if (!clientSocket) clientSocket = socket;
        }
    });

    socket.on("error", (err) => {
        console.error("Proxy error: could not connect with client");
    });
});

const port = process.env.PORT || 4000;

proxyServer.listen(port, () => {
    console.log(`Proxy Server is running on port ${port}`);
});

httpServer.listen(4444, () => {
    console.log("Http server is running on port 4444");
});

thank you for helping.

obeda
  • 82
  • 10
  • Does this answer your question? [Error: Can't set headers after they are sent to the client](https://stackoverflow.com/questions/7042340/error-cant-set-headers-after-they-are-sent-to-the-client) – jasonandmonte Sep 23 '20 at 02:18

2 Answers2

0

You are calling res.send() on every "ed" event and you're emitting an "ed" event on every clientSocket.on('data', ...) event. So, as soon as you get a second data event you'll be trying to call res.send() for the second time on the same response. You only get one response per http request. You can't call res.send() more than once for a given http response.

It's unclear how this code is supposed to work since I don't know what you're really trying accomplish here. Perhaps you need to accumulate all the data from the data events and then send one response and then unhook all the listeners do you don't get any more data events for this request. Or, if you want to send the response on the first data event, then just unhook the data and ed listeners after you send the response.

Keep in mind that on a regular socket, you have no control over what data comes in a data event. TCP is a stream protocol and data can come in any size chunks and the chunks it arrives in may not be the exact same as the chunks it was sent in. You would typically have to be looking for some sort of complete packet yourself and be able to assemble or split data events into full packets you can do something with.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • thank you for your help, I am new to StackOverflow so I apologize for missing information I ended using a promise and missing return statement to solve this problem – obeda Sep 23 '20 at 18:52
0

Generally this error "Cannot set headers after they are sent to the client" occurs when you are sending multiple response to the server. In your case,

eventEminter.on("ed", () => {
        res.send(clientData);
    });

As you are using this, you are sending multiple response to server. You should send the response only once. You can use this code instead

eventEminter.once('ed', () => {
  res.send(clientData);
});
Dharman
  • 30,962
  • 25
  • 85
  • 135