Search code examples
node.jsaxiosresponse-headersssh2

Getting "Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client" while using Axios


I am trying to use different Axios calls to get some data from a remote server. One by one the calls are working but as soons as I call them directly after each other its throwing the error message about the headers. I did some research already and I guess it has sth to do that there the headers of the first call gets in the way of the second call. That is probably a very simplematic description of the problem but I am new to node js and the way those axios calls are working.

This is an example of one of my Api calls:

app.get('/api/ssh/feedback', function(req, res){
    conn.on('ready', function(){
        try {
            let allData = {}
            var command = 'docker ps --filter status=running --format "{{.Names}}"'
            conn.exec(command, function(err, stream){
                if (err) throw console.log(err)
                stream.on('data', function(data){
                    allData = data.toString('utf8').split('\n').filter(e=>e)
                    return res.json({status: true, info: allData})
                })
                stream.on('close', function(code){
                    console.log('Process closed with: ' + code)
                    conn.end()
                })
                stream.on('error', function(err){
                    console.log('Error: ' + err)
                    conn.end()
                })
            })
        } catch (err) {
            console.error('failed with: ' + err)
 
        }
    }).connect(connSet)
})

I am using express js as a middleware and the shh2 package to get the connection with the remote server. How I mentioned before the call is working but crashes if it is not the first call. I am able to use the api again after I restart the express server.

This is how I am calling the api through axios in my node js frontend:

getNetworkStatus(e){
        e.preventDefault()
        axios.get('/api/ssh/network').then(res =>{
            if(res.data.status){
                this.setState({network_info: 'Running'})
                this.setState({network: res.data.info})
            } else {
                this.setState({network_info: 'No Network Running'})
                this.setState({network: 'No Network detected'})
            }
        }).catch(err => {
            alert(err)
        })
    }

I would be really grateful for any help or advice how to solve this problem. Thanks to everyone who spends some time to help me out.


Solution

  • There are two issues in the code you've provided:

    1. You are making assumptions about 'data' events. In general, never assume the size of the chunks you receive in 'data' events. You might get one byte or you might get 1000 bytes. The event can be called multiple times as chunks are received and this is most likely what is causing the error. Side note: if the command is only outputting text, then you are better off using stream.setEncoding('utf8') (instead of manually calling data.toString('utf8')) as it will take care of multi-byte characters that may be split across chunks.

    2. You are reusing the same connection object. This is a problem because you will continue to add more and more event handlers every time that HTTP endpoint is reached. Move your const conn = ... inside the endpoint handler instead. This could also be causing the error you're getting.