Как я могу использовать http-прокси с node.js http.Client?

Я хочу сделать исходящий HTTP-вызов из node.js, используя стандартный http.Client. Но я не могу подключиться к удаленному серверу напрямую из моей сети, и мне нужно пройти через прокси.

Как мне сказать node.js использовать прокси?


person Christian Berg    schedule 05.10.2010    source источник
comment
У меня такая же проблема. Node.js находится за брандмауэром, и я не могу создать HTTPClient для внешнего веб-сайта.   -  person ddallala    schedule 28.12.2010


Ответы (18)


Тим Макфарлейн: ответ был близок к использованию прокси-сервера HTTP.

Использовать HTTP-прокси (для незащищенных запросов) очень просто. Вы подключаетесь к прокси-серверу и делаете запрос в обычном режиме, за исключением того, что часть пути включает полный URL-адрес, а заголовок хоста установлен на хост, к которому вы хотите подключиться.
Тим был очень близок со своим ответом, но он пропустил настройку хоста заголовок правильно.

var http = require("http");

var options = {
  host: "proxy",
  port: 8080,
  path: "http://www.google.com",
  headers: {
    Host: "www.google.com"
  }
};
http.get(options, function(res) {
  console.log(res);
  res.pipe(process.stdout);
});

Для записи его ответ действительно работает с http://nodejs.org/, но это потому, что их сервер не заботится о заголовок хоста неверен.

person Samuel    schedule 21.07.2011
comment
Есть ли способ использовать http-прокси для подключения https-порта? кажется, нет простого метода - person Gohan; 30.12.2011
comment
@Gohan См. Ответ Криса ниже, чтобы узнать, как подключиться к https-серверу через http-прокси. - person HairOfTheDog; 19.07.2012
comment
если вы получили неверный запрос, укажите путь: '/' - person Laurent Debricon; 01.06.2013
comment
Как я могу интегрировать прокси-пользователя и прокси-пароль в блок опций? - person Twistleton; 11.04.2014
comment
Это изменилось? Даже если конечным пунктом назначения является другой локальный сервер, я получаю 404, а целевой сервер никогда не получает запрос .. - person OJFord; 04.08.2015
comment
Как этого добиться на глобальном уровне? Я могу делать это по отдельным запросам, но у меня есть vendor модулей, которые мне также нужно использовать через прокси-соединение. - person Andi Giga; 21.03.2016
comment
Я получаю эту ошибку с кодом выше Ошибка: прокси-сервер getaddrinfo ENOTFOUND: 8080 - person VVB; 27.10.2017
comment
Даже без использования прокси это не работает. Я не думаю, что поле пути можно использовать таким образом, я получаю сообщение об отказе в соединении с options = { path: "http://www.example.com/", method: "GET", headers: {Host: "www.example.com"}}. - person Jack M; 27.10.2018
comment
@Samuel привет, можешь посмотреть мой вопрос stackoverflow.com/questions/53593182/? Я не могу заставить твое решение работать. - person Qiulang; 01.09.2020

Вы можете использовать request, я только что обнаружил, что использовать прокси на node.js невероятно просто, всего лишь с одним внешним параметр "прокси", даже более того, он поддерживает HTTPS через http прокси.

var request = require('request');

request({
  'url':'https://anysite.you.want/sub/sub',
  'method': "GET",
  'proxy':'http://yourproxy:8087'
},function (error, response, body) {
  if (!error && response.statusCode == 200) {
    console.log(body);
  }
})
person Imskull    schedule 22.01.2014
comment
В моем случае работал как для http, так и для https, большое спасибо - person Samuel Bushi; 29.06.2015
comment
есть идеи, почему это не сработает для внутренних корпоративных страниц? - person keinabel; 03.07.2015
comment
Я удивлен, что внутренние корпоративные страницы находятся за прокси. Вы уверены, что прокси не обходится для внутренних страниц? Это на другом влане? - person Chanoch; 11.08.2015
comment
Вам нужно как-то указать аутентификацию (выложу здесь, если я это выясню) - person Igor L.; 31.03.2016
comment
Я получил эту ошибку, используя запрос с прокси: Ошибка: туннельный сокет не может быть установлен, причина = connect ECONNREFUSED 127.0.0.1:80 - person Federico Caccia; 10.07.2020
comment
@IgorL. Я заставил его работать с Auth и модулем запроса, с headers: {'Proxy-Authorization': XXXX} - person Aaron McKeehan; 27.10.2020
comment
Если прокси-сервер не HTTPS, разве это не небезопасно (пароль в открытом виде)? - person Learner; 30.01.2021

Мне потребовалось время, чтобы понять одну вещь: использовать http для доступа к прокси-серверу, даже если вы пытаетесь прокси-сервером на https-сервер. Это работает для меня, используя Charles (анализатор протокола osx):

var http = require('http');

http.get ({
    host: '127.0.0.1',
    port: 8888,
    path: 'https://www.google.com/accounts/OAuthGetRequestToken'
}, function (response) {
    console.log (response);
});
person Chris    schedule 16.06.2011
comment
Приведенный выше код не работает для меня и связан с проблемой github.com/joyent/node/issues / 2474 проверьте ответ koichik, мы должны использовать метод: connect, и при событии подключения мы отправляем информацию о пути. - person Palani; 28.08.2014

Как уже упоминал @Renat, проксируемый HTTP-трафик поступает в виде вполне обычных HTTP-запросов. Сделайте запрос к прокси, передав в качестве пути полный URL места назначения.

var http = require ('http');

http.get ({
    host: 'my.proxy.com',
    port: 8080,
    path: 'http://nodejs.org/'
}, function (response) {
    console.log (response);
});
person Community    schedule 27.04.2011
comment
Кажется, это работает, хотя Fiddler называет это нарушением протокола, что предполагает, что это не правильный HTTP-запрос через прокси ... - person Marc; 10.09.2011

Купил приватный прокси-сервер, после покупки получил:

255.255.255.255 // IP address of proxy server
99999 // port of proxy server
username // authentication username of proxy server
password // authentication password of proxy server

И я хотел этим воспользоваться. Первый ответ и второй ответ работал только для http (прокси) - ›http (пункт назначения), однако я хотел http (прокси) -› https (пункт назначения).

А для назначения https было бы лучше использовать напрямую HTTP-туннель. Я нашел решение здесь.

Узел v8:

const http = require('http')
const https = require('https')
const username = 'username'
const password = 'password'
const auth = 'Basic ' + Buffer.from(username + ':' + password).toString('base64')

http.request({
  host: '255.255.255.255', // IP address of proxy server
  port: 99999, // port of proxy server
  method: 'CONNECT',
  path: 'kinopoisk.ru:443', // some destination, add 443 port for https!
  headers: {
    'Proxy-Authorization': auth
  },
}).on('connect', (res, socket) => {
  if (res.statusCode === 200) { // connected to proxy server
    https.get({
      host: 'www.kinopoisk.ru',
      socket: socket,    // using a tunnel
      agent: false,      // cannot use a default agent
      path: '/your/url'  // specify path to get from server
    }, (res) => {
      let chunks = []
      res.on('data', chunk => chunks.push(chunk))
      res.on('end', () => {
        console.log('DONE', Buffer.concat(chunks).toString('utf8'))
      })
    })
  }
}).on('error', (err) => {
  console.error('error', err)
}).end()

Узел v14:

const http = require('http');
const https = require('https');
const username = 'username';
const password = 'password';
const auth = 'Basic ' + Buffer.from(username + ':' + password).toString('base64');

http.request({
  host: '255.255.255.255', // IP address of proxy server
  port: 99999, // port of proxy server
  method: 'CONNECT',
  path: 'kinopoisk.ru:443', // some destination, add 443 port for https!
  headers: {
    'Proxy-Authorization': auth
  },
}).on('connect', (res, socket) => {
  if (res.statusCode === 200) { // connected to proxy server
    const agent = new https.Agent({ socket });
    https.get({
      host: 'www.kinopoisk.ru',
      path: '/',
      agent,      // cannot use a default agent
    }, (res) => {
      let chunks = []
      res.on('data', chunk => chunks.push(chunk))
      res.on('end', () => {
        console.log('DONE', Buffer.concat(chunks).toString('utf8'))
      })
    })
  }
}).on('error', (err) => {
  console.error('error', err)
}).end();
person Alexey Volodko    schedule 02.04.2018
comment
Свойство socket не задокументировано в nodejs. Была ли удалена эта опция. - person CMCDragonkai; 02.04.2021
comment
Описанный подход в настоящее время не работает. Параметр socket не поддерживается функциями get / request модулей http модулей и просто игнорируется. - person Damaged Organic; 14.06.2021
comment
Обновленный код для узла v14 - person Alexey Volodko; 15.06.2021

Думал, что добавлю этот модуль, который нашел: https://www.npmjs.org/package/global-tunnel, который отлично работал у меня (работал сразу со всем моим кодом и сторонними модулями, используя только код ниже).

require('global-tunnel').initialize({
  host: '10.0.0.10',
  port: 8080
});

Сделайте это один раз, и весь http (и https) в вашем приложении будет проходить через прокси.

Поочередно звонить

require('global-tunnel').initialize();

Будет использоваться переменная среды http_proxy

person major-mann    schedule 04.08.2014
comment
Это сработало для меня! Фактически, таким образом вы отделяете прокси от кода и используете существующую конфигурацию для npm! это путь, я бы сказал - person cesaregb; 08.02.2015
comment
@NeelBasu Да, это так - person major-mann; 11.05.2017

Кажется, что у http-пакета 'request' есть такая функция:

https://github.com/mikeal/request

Например, объект запроса 'r' ниже использует localproxy для доступа к своим запросам:

var r = request.defaults({'proxy':'http://localproxy.com'})

http.createServer(function (req, resp) {
  if (req.url === '/doodle.png') {
    r.get('http://google.com/doodle.png').pipe(resp)
  }
})

К сожалению, не существует "глобальных" значений по умолчанию, поэтому пользователи библиотек, которые используют это, не могут изменять прокси, если библиотека не проходит через параметры http ...

HTH, Крис

person Chris Kimpton    schedule 14.10.2012
comment
пакет http запроса упрощает переключение вашего кода между использованием прокси и не прокси (что весьма полезно на моем ноутбуке). - person Jon Madison; 29.04.2015

Если вам нужно использовать базовую авторизацию для вашего прокси-провайдера, просто используйте следующее:

var http = require("http");

var options = {
    host:       FarmerAdapter.PROXY_HOST,
    port:       FarmerAdapter.PROXY_PORT,
    path:       requestedUrl,
    headers:    {
        'Proxy-Authorization':  'Basic ' + new Buffer(FarmerAdapter.PROXY_USER + ':' + FarmerAdapter.PROXY_PASS).toString('base64')
    }
};

var request = http.request(options, function(response) {
    var chunks = [];
    response.on('data', function(chunk) {
        chunks.push(chunk);
    });
    response.on('end', function() {
        console.log('Response', Buffer.concat(chunks).toString());
    });
});

request.on('error', function(error) {
    console.log(error.message);
});

request.end();
person Vyacheslav Voronchuk    schedule 19.01.2016
comment
где я могу найти FarmerAdapter? - person Manjeet; 18.07.2016

По сути, вам не нужна явная поддержка прокси. Протокол прокси довольно прост и основан на обычном протоколе HTTP. Вам просто нужно использовать свой прокси-хост и порт при подключении к HTTPClient. Пример (из документации node.js):

var http = require('http');
var google = http.createClient(3128, 'your.proxy.host');
var request = google.request('GET', '/',
  {'host': 'www.google.com'});
request.end();
...

В основном вы подключаетесь к своему прокси, но делаете запрос на «http://www.google.com».

person Renat    schedule 04.11.2010
comment
http.createClient устарел, Тим Макфарлейн использует более новый http.get ниже - person sami; 15.06.2011
comment
По-видимому, это больше не будет работать с node.js начиная с v5.6, поскольку они удалили createClient. - person Marc; 10.09.2011

Узел должен поддерживать использование переменной окружения http_proxy, поэтому он является кроссплатформенным и работает с настройками системы, а не требует конфигурации для каждого приложения.

Используя предоставленные решения, я бы рекомендовал следующее:

Coffeescript

get_url = (url, response) ->
  if process.env.http_proxy?
    match = process.env.http_proxy.match /^(http:\/\/)?([^:\/]+)(:([0-9]+))?/i
    if match
      http.get { host: match[2], port: (if match[4]? then match[4] else 80), path: url }, response
      return
  http.get url, response

Javascript

get_url = function(url, response) {
  var match;
  if (process.env.http_proxy != null) {
    match = process.env.http_proxy.match(/^(http:\/\/)?([^:\/]+)(:([0-9]+))?/i);
    if (match) {
      http.get({
        host: match[2],
        port: (match[4] != null ? match[4] : 80),
        path: url
      }, response);
      return;
    }
  }
  return http.get(url, response);
};

Использование Чтобы использовать этот метод, просто замените http.get, например, следующее записывает индексную страницу Google в файл с именем test.htm:

file = fs.createWriteStream path.resolve(__dirname, "test.htm")
get_url "http://www.google.com.au/", (response) ->
  response.pipe file
  response.on "end", ->
    console.log "complete"
person Luke    schedule 13.08.2013
comment
Установка http_proxy не оказывает никакого эффекта при запуске Node в Windows. - person EricLaw; 07.01.2014
comment
Он должен работать под Windows (это основная система, которую я использую). Убедитесь, что после того, как вы установили параметр, вы сбросили сеанс терминала (если он установлен через панель управления, а не установлен). Вы должны иметь возможность проверить его правильность, используя echo% HTTP_PROXY%. Или, что еще лучше, вы должны использовать сам узел node -e console.log (process.env.http_proxy); У меня это сработало под Windows, так что удачи. - person Luke; 07.01.2014

Я думаю, что есть лучшая альтернатива ответам на 2019 год. Мы можем использовать пакет global-tunnel-ng для инициализации прокси и не загрязнять везде код на основе http или https. Итак, сначала установите пакет global-tunnel-ng:

npm install global-tunnel-ng

Затем измените свои реализации, чтобы инициализировать прокси-сервер, если необходимо:

const globalTunnel = require('global-tunnel-ng');

globalTunnel.initialize({
  host: 'proxy.host.name.or.ip',
  port: 8080
});
person ring bearer    schedule 04.03.2019

Ответ Имскалла почти сработал для меня, но мне пришлось внести некоторые изменения. Единственное реальное изменение - это добавление имени пользователя, пароля и установка для rejectUnauthorized значения false. Я не мог комментировать, поэтому вставил это в ответ.

Если вы запустите код, он предоставит вам заголовки текущих статей в Hacker News, согласно этому руководству: http://smalljs.org/package-managers/npm/

var cheerio = require('cheerio');
var request = require('request');

request({
    'url': 'https://news.ycombinator.com/',
    'proxy': 'http://Username:Password@YourProxy:Port/',
    'rejectUnauthorized': false
}, function(error, response, body) {
    if (!error && response.statusCode == 200) {
        if (response.body) {
            var $ = cheerio.load(response.body);
            $('td.title a').each(function() {
                console.log($(this).text());
            });
       }
    } else {
        console.log('Error or status not equal 200.');
    }
});
person Vasily Kushakov    schedule 25.05.2016


Возможно, это не тот однострочный текст, на который вы рассчитывали, но вы можете взглянуть на http://github.com/nodejitsu/node-http-proxy, поскольку это может пролить свет на то, как вы можете использовать свое приложение с http.Client.

person fullstacklife    schedule 10.10.2010
comment
Чем это полезно? - person Jerinaw; 13.05.2019


Для использования прокси с https я попробовал совет на этом веб-сайте (используя зависимость https-proxy-agent), и у меня это сработало:

http://codingmiles.com/node-js-making-https-request-via-proxy/

person Jonathan Benn    schedule 06.04.2017

используйте https-proxy-agent вот так

var HttpsProxyAgent = require('https-proxy-agent');
var proxy = process.env.https_proxy || 'other proxy address';
var agent = new HttpsProxyAgent(proxy);

options = {
    //...
    agent : agent
}

https.get(options, (res)=>{...});
person Bad Green    schedule 28.11.2017

Если у вас есть Базовый Схема аутентификации http, вы должны сделать строку base64 myuser:mypassword, а затем добавить "Базовая" в начале. Это значение заголовка Proxy-Authorization. , вот пример:

var Http = require('http');

var req = Http.request({
    host: 'myproxy.com.zx',
    port: 8080,
    headers:{"Proxy-Authorization": "Basic bXl1c2VyOm15cGFzc3dvcmQ="},
    method: 'GET',
    path: 'http://www.google.com/'
    }, function (res) {
        res.on('data', function (data) {
        console.log(data.toString());
    });
});

req.end();

В nodejs вы можете использовать Buffer для кодирования

var encodedData = Buffer.from('myuser:mypassword').toString('base64');

console.log(encodedData);

Например, в браузерах вы можете кодировать в base64, используя btoa ( ), полезно в запросах ajax в браузере без настроек прокси, выполняя запрос через прокси.

var encodedData = btoa('myuser:mypassword')

console.log(encodedData);

Как узнать, какая схема принимает прокси-сервер?

Если у нас не настроен настраиваемый DNS (который будет выдавать что-то вроде ERR_NAME_NOT_RESOLVED), когда мы выполняем запрос, ответ (код 407) должен сообщать в заголовках ответов, какую схему HTTP-аутентификации использует прокси.

person Emeeus    schedule 03.05.2018