简体   繁体   中英

Connection not closing using http with node.js

I have written the following function in Node.js in order to get json data from another server, with a view to saving it in a database and doing further processing. The current function is:

const db = require('../models/db.js')    
const gameHistDB = db.gameHistDB
const gameControlDB = db.gameControlDB
const http = require('http')

const playMove = async (req, res) => {
    try{
        console.log("playing")
        var playOptions = {
            hostname:'115.146.93.216',
            port: 5000,
            path: '/action/a159257a6840135d2edd5a3de3017356/game1/46',
            method: 'GET',
            agent:false,
            Connection:'close'
        }
        console.log(playOptions.path)
        var returnedData;
        var req = http.request(playOptions, res => {
            console.log(res.statusCode)

            let data = ''
            res.on('data',(d) => {
                data += d;
                console.log(d)
            });

            res.on('close',()=>{
                returnedData = JSON.parse(data)
                console.log(returnedData.turninfo.gamestep)
                // gameHistDB.insert(returnedData)
            });

        })

        req.on('error',error => {
            console.error(error)
        })

        req.end()
        console.log('Note that we got here')

    } catch (err) {
        console.log(err)
    }
}

(this is possibly a little more complex than it needs to be, but I'm trying to see exactly what is happening at what point)

When I invoke this the browser hangs in "getting data" mode and doesn't seem to get to a state where it thinks all the data has been processed, although it is definitely going into the 'on close' block and logging the right data. If I uncomment the code which is inserting the requested json into the database then very nasty stuff happens, with constant nano errors telling me to revalidate the cache.

I'm also unsure whether it's good workflow to do the database queries within res.on('close') - in other functions where I'm dealing with db queries I'm using await to ensure the query completes before doing other stuff, but it seems like I can't do that here.

Any help appreciated

EDIT: As in comments, I think maybe it is the json sending code on the other machine which is at fault. That is:

try{
    console.log("playing")

    ...

    const python = spawn('python3',['./playGameMove.py',JSON.stringify(gamestep),req.params.move]);
    python.stdout.on('data',function(data){
        console.log('Getting data from playGameMove.py');
        nextState.push(data);
    });
    python.on('close',(code) => {
        console.log('in close');
        res.send(nextState.join(""))
    });
}catch(err){
    console.log(err)
}

Is there something I should do after res.send to ensure this code knows that it's done?

There are three main problems with your code.

  1. You are naming two "req" and two "res"
  2. The execution order is not what you think. You are closing the request immediately, before anything happens (welcome to the world of asynchronism)
  3. You are not replying to the browser, which leaves it hanging.

Below are comments about all that's wrong with your current code. (I have removed the try/catch block because it's useless, you have error management with req.on('error') , nothing else should fail)

const playMove = async (req, res) => { // No need for the "async" keyword. You're not using its counterpart, "await".

    var playOptions = { /* ... */ }
    var returnedData;

    // Problem here, you have called "req" like the other "req" from line 1. Now you have two "req"... Which is which?
    var req = http.request(playOptions, res => { // Executed 1st

        // Problem here, you have called "res" like the other "res" from line 1. Now you have two "res"... Which is which?

        console.log(res.statusCode)  // Executed 5th

        let data = ''
        res.on('data', (d) => {  // Executed 6th
            data += d;
            console.log(d)  // Executed 7th, 7th, 7th, every time there's a data coming in
        });

        res.on('close', () => { // Executed 8th
            returnedData = JSON.parse(data) // Executed 9th
            console.log(returnedData.turninfo.gamestep) // Executed 10th
            // gameHistDB.insert(returnedData)
        });

    })

    req.on('error', error => {  // Executed 2nd
        console.error(error)
    })

    req.end()  // Executed 3rd

    console.log('Note that we got here')  // Executed 4th
}

Here's a corrected version :

const playMove = (req, res) => {

    var playOptions = { /* ... */ }
    var returnedData;

    var reqHTTP = http.request(playOptions, resHTTP => { // Executed 1st. Using different names to not mix things up.

        console.log(resHTTP.statusCode)  // Executed 4th

        let data = ''
        resHTTP.on('data', (d) => {  // Executed 5th
            data += d;
            console.log(d)  // Executed 6th, 6th, 6th, every time there's a data coming in
        });

        resHTTP.on('close', () => { // Executed 7th
            returnedData = JSON.parse(data) // Executed 8th
            console.log(returnedData.turninfo.gamestep) // Executed 9th
            // gameHistDB.insert(returnedData)
            reqHTTP.end()  // Executed 10th

            res.send(returnedData); // Now reply to the browser! Executed 11th
        });

    })

    req.on('error', error => {  // Executed 2nd
        console.error(error)
    })

    console.log('Note that we got here')  // Executed 3rd
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM