Довольно часто программируя на 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