Search code examples
javascriptnode.jsmodel-view-controllerweb-deploymentkoa2

How to get response body from a http.request as a ctx.body for koa?


I'm learning Node.js, and for some reason I need to set up a http.request to another ip, and get the response from it and apply to ctx.body of koa. I wrote the code like this:

var refreshData = async (ctx, next) =>{
    var option = {
        host: 'xxx.xxx.xxx.xxx',
        port: 8080,
        path: '/reqPath',
        method: 'POST',
        headers:{'Content-Type': 'application/json'}
    };

    var postData = "1";
    var resData = '';
    var req = http.request(option, function(res){
        res.setEncoding('utf8');        
        res.on('data', function (chunk) {
            resData = resData + 'Chunk: ' + chunk;
        });
        res.on('end', function(){
            ctx.res.body = resData;
            console.log('ResponseData: ' + ctx.res.body);    //shows the correct data
        });
    });

    req.on('error', function(e){
        console.log('problem with request: ' + e.message);
    });

    req.write(postData);
    req.end();      
};

module.exports = {
    'GET /refreshDataGet': refreshData,
};

Learning to use controller mapping and it works, and resData is the correct data. But I can only get 'status 0' when doing the 'GET /refreshDataGet' from the webpage. If I don't do the http.request and directly apply a JSON object to ctx.body, I can get the correct status and data on the webpage. Did I miss something? Or there is a better solution to act this?

Thanks!!


Edit: return 404, if manually set to 200 then find nothing in the response body. But the debug print is correct inside

res.on('end', function(){})


Solution

  • The problem here is the following: within your async function, you are defining a callback function. This will lead to your 404, because the ascny / await pattern requires promises ... So what you basically have to do is to wrap your http.request into another funttion which returns a promise. So something like:

    // not tested !!
    function getHttpRequest() {
        let option = {
            host: 'xxx.xxx.xxx.xxx',
            port: 8080,
            path: '/reqPath',
            method: 'POST',
            headers:{'Content-Type': 'application/json'}
        };
    
        return new Promise((resolve, reject) => {
    
            let postData = "1";
            let resData = '';
            let req = http.request(option, function(res){
                res.setEncoding('utf8');        
                res.on('data', function (chunk) {
                    resData = resData + 'Chunk: ' + chunk;
                });
                res.on('end', function(){
                    resolve(resData)
                });
            });    
        })
    }
    

    Then in your refreshData async function you are awaiting the resolving promise like:

    ctx.body = await getHttpRequest():
    

    Hope that helps ...