Создание простых HTTP запросов без зависимостей используя Promise

Довольно часто программируя на Node.JS приходиться выполнять различного рода HTTP запросы. Для этого использую библиотеку Request, но иногда возникают ситуации, когда запрос нужно выполнить определённым образом и это становится определённой проблемой. В итоге решил написать свой маленький модуль, который решает данную проблему.

let url   = require('url'),
    http  = require('http'),
    https = require('https')

let REDIRECTS_FOLLOWED = 0

const REQUEST_TIMEOUT   = 5000,
      REDIRECTS_MAXIMUM = 5

function doRequest (_url, options = {}) {
    const lib = _url.startsWith('https') ? https : http

    if (Object.prototype.toString.call(options) != '[object Object]') {
        options = {}
    }

    if ('headers' in options == false) {
        options.headers = {}
    }

    if ('User-Agent' in options.headers == false) {
        options.headers['User-Agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/602.2.14 (KHTML, like Gecko) Version/10.0.1 Safari/602.2.14'
    }

    if ('data' in options && ('Content-Length' in options.headers) == false) {
        options.headers['Content-Length'] = Buffer.byteLength(data)
    }

    if ('proxy' in options) {
        let proxy = options.proxy
            proxy = proxy.split(':')

        options.host = proxy[0]
        options.port = proxy[1]
        options.path = _url
    } else {
        let parsed_url = url.parse(_url)

        options.host = parsed_url.host
        options.path = parsed_url.path
    }

    return new Promise(function(resolve, reject) {
        let request = lib.request(options, function(response) {
            if (response.statusCode >= 500) {
                request.abort()

                reject(new Error('Failed to load page, status code: ' + response.statusCode))
            }

            if (response.statusCode > 300 && response.statusCode < 400 && response.headers.location) {
                if (url.parse(response.headers.location).hostname == false) {
                    let parsed_url = url.parse(_url)

                    response.headers.location = url.resolve(parsed_url.host, response.headers.location)
                }

                if (REDIRECTS_FOLLOWED >= REDIRECTS_MAXIMUM) {
                    reject(new Error('Exceeded maximum redirects. Probably stuck in a redirect loop ' +  response.headers.location))

                    return false
                }

                REDIRECTS_FOLLOWED++

                console.log('#%d Redirect To: %s', REDIRECTS_FOLLOWED,  response.headers.location)

                doRequest(response.headers.location, options).then(function(result) {
                    resolve(result)
                }).catch(function(err) {
                    reject(err)
                })
            } else {
                let body = [];

                response.on('data', function(chunk) {
                    body.push(chunk)
                })

                response.on('end', function() {
                    resolve({
                        response: response,
                        body: body.join('')
                    })
                })
            }
        })

        request.setTimeout(REQUEST_TIMEOUT, function() {
            request.abort()

            reject(new Error('Timeout'))
        })

        request.on('error', function(err) {
            reject(err)
        })

        if ('data' in options) {
            request.write(data)
        }

        request.end()
    })
}

Пример

let opt = {
    headers: {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/55.0.2883.87 Chrome/55.0.2883.87 Safari/537.36'},
    data: 'some_string' // будет POST
}

doRequest('http://nonamez.name').then(function(result) {
    // console.log(result.response)
    // console.log(result.body)
}).catch(function(error) {
    // console.log(error)
})

Более развёрнутую версию можно найти на GitHub

Fork me on GitHub