nodejs - How to promisify http.request? reject got called two times

后端 未结 5 633
难免孤独
难免孤独 2020-11-29 20:37

I\'m trying to wrap http.request into Promise:

 new Promise(function(resolve, reject) {
    var req = http.request({
        host:          


        
相关标签:
5条回答
  • 2020-11-29 21:20

    There are other ways as well but here you can find a simple way to make http.request as a promise or async/await type.

    Here is a working sample code:

    var http = require('http');
    
    function requestAsync(name) {
    
        return new Promise((resolve, reject) => {
            var post_options = {
                host: 'restcountries.eu',
                port: '80',
                path: `/rest/v2/name/${name}`,
                method: 'GET',
                headers: {
                    'Content-Type': 'application/json'
                }
            };
            let post_req = http.request(post_options, (res) => {
                res.setEncoding('utf8');
                res.on('data', (chunk) => {
                    resolve(chunk);
                });
                res.on("error", (err) => {
                    reject(err);
                });
            });
            post_req.write('test');
            post_req.end();
        });
    }
    
    //Calling request function
    //:1- as promise
    requestAsync("india").then(countryDetails => {
        console.log(countryDetails);
    }).catch((err) => {
        console.log(err);  
    }); 
    
    //:2- as await
    let countryDetails = await requestAsync("india");
    
    0 讨论(0)
  • 2020-11-29 21:36

    Your code is almost fine. To restate a little, you want a function that wraps http.request with this form:

    function httpRequest(params, postData) {
        return new Promise(function(resolve, reject) {
            var req = http.request(params, function(res) {
                // on bad status, reject
                // on response data, cumulate it
                // on end, parse and resolve
            });
            // on request error, reject
            // if there's post data, write it to the request
            // important: end the request req.end()
        });
    }
    

    Notice the addition of params and postData so this can be used as a general purpose request. And notice the last line req.end() -- which must always be called -- was missing from the OP code.

    Applying those couple changes to the OP code...

    function httpRequest(params, postData) {
        return new Promise(function(resolve, reject) {
            var req = http.request(params, function(res) {
                // reject on bad status
                if (res.statusCode < 200 || res.statusCode >= 300) {
                    return reject(new Error('statusCode=' + res.statusCode));
                }
                // cumulate data
                var body = [];
                res.on('data', function(chunk) {
                    body.push(chunk);
                });
                // resolve on end
                res.on('end', function() {
                    try {
                        body = JSON.parse(Buffer.concat(body).toString());
                    } catch(e) {
                        reject(e);
                    }
                    resolve(body);
                });
            });
            // reject on request error
            req.on('error', function(err) {
                // This is not a "Second reject", just a different sort of failure
                reject(err);
            });
            if (postData) {
                req.write(postData);
            }
            // IMPORTANT
            req.end();
        });
    }
    

    This is untested, but it should work fine...

    var params = {
        host: '127.0.0.1',
        port: 4000,
        method: 'GET',
        path: '/api/v1/service'
    };
    // this is a get, so there's no post data
    
    httpRequest(params).then(function(body) {
        console.log(body);
    });
    

    And these promises can be chained, too...

    httpRequest(params).then(function(body) {
        console.log(body);
        return httpRequest(otherParams);
    }).then(function(body) {
        console.log(body);
        // and so on
    });
    
    0 讨论(0)
  • 2020-11-29 21:36

    I know this question is old but the answer actually inspired me to write a modern version of a lightweight promisified HTTP client. Here is a new version that:

    • Use up to date JavaScript syntax
    • Validate input
    • Support multiple methods
    • Is easy to extend for HTTPS support
    • Will let the client decide on how to deal with response codes
    • Will also let the client decided on how to deal with non-JSON bodies

    Code below:

    function httpRequest(method, url, body = null) {
        if (!['get', 'post', 'head'].includes(method)) {
            throw new Error(`Invalid method: ${method}`);
        }
    
        let urlObject;
    
        try {
            urlObject = new URL(url);
        } catch (error) {
            throw new Error(`Invalid url ${url}`);
        }
    
        if (body && method !== 'post') {
            throw new Error(`Invalid use of the body parameter while using the ${method.toUpperCase()} method.`);
        }
    
        let options = {
            method: method.toUpperCase(),
            hostname: urlObject.hostname,
            port: urlObject.port,
            path: urlObject.pathname
        };
    
        if (body) {
            options.headers = {'Content-Length':Buffer.byteLength(body)};
        }
    
        return new Promise((resolve, reject) => {
    
            const clientRequest = http.request(options, incomingMessage => {
    
                // Response object.
                let response = {
                    statusCode: incomingMessage.statusCode,
                    headers: incomingMessage.headers,
                    body: []
                };
    
                // Collect response body data.
                incomingMessage.on('data', chunk => {
                    response.body.push(chunk);
                });
    
                // Resolve on end.
                incomingMessage.on('end', () => {
                    if (response.body.length) {
    
                        response.body = response.body.join();
    
                        try {
                            response.body = JSON.parse(response.body);
                        } catch (error) {
                            // Silently fail if response is not JSON.
                        }
                    }
    
                    resolve(response);
                });
            });
    
            // Reject on request error.
            clientRequest.on('error', error => {
                reject(error);
            });
    
            // Write request body if present.
            if (body) {
                clientRequest.write(body);
            }
    
            // Close HTTP connection.
            clientRequest.end();
        });
    }
    
    0 讨论(0)
  • 2020-11-29 21:39

    It's easier for you to use bluebird api, you can promisify request module and use the request function async as a promise itself, or you have the option of using the module request-promise, that makes you to not working to creating a promise but using and object that already encapsulates the module using promise, here's an example:

    var rp = require('request-promise');
    
    rp({host: '127.0.0.1',
        port: 4000,
        method: 'GET',
        path: '/api/v1/service'})
        .then(function (parsedBody) {
            // GET succeeded... 
        })
        .catch(function (err) {
            // GET failed... 
        });
    
    0 讨论(0)
  • 2020-11-29 21:42

    Hope this help.

    const request = require('request');
    
    async function getRequest() {
      const options = {
        url: 'http://example.com',
        headers: {
          'Authorization': 'Bearer xxx'
        }
      };
    
      return new Promise((resolve, reject) => {
        return request(options, (error, response, body) => {
          if (!error && response.statusCode == 200) {
            const json = JSON.parse(body);
            return resolve(json);
          } else {
            return reject(error);
          }
        });
      })
    }
    
    0 讨论(0)
提交回复
热议问题