¿Cómo puedo usar un proxy HTTP con node.js http.Client?

137

Quiero hacer una llamada HTTP saliente desde node.js, usando el estándar http.Client. Pero no puedo acceder al servidor remoto directamente desde mi red y necesito pasar por un proxy.

¿Cómo le digo a node.js que use el proxy?

Christian Berg
fuente
1
Estoy teniendo el mismo problema Node.js está detrás de un firewall y no puedo crear un HTTPClient en un sitio web externo.
ddallala

Respuestas:

153

La respuesta de Tim Macfarlane fue cercana con respecto al uso de un proxy HTTP.

Usar un proxy HTTP (para solicitudes no seguras) es muy simple. Se conecta al proxy y realiza la solicitud normalmente, excepto que la parte de la ruta incluye la url completa y el encabezado del host está configurado para el host al que desea conectarse.
Tim estuvo muy cerca con su respuesta, pero no pudo configurar el encabezado del host correctamente.

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);
});

Para el registro, su respuesta funciona con http://nodejs.org/ pero eso se debe a que a su servidor no le importa que el encabezado del host sea incorrecto.

Samuel
fuente
1
¿Hay alguna manera de usar el puerto HTTP https connect https? parece que no tiene un método fácil
Gohan
@Gohan Consulte la respuesta de Chris a continuación para ver un ejemplo sobre cómo conectarse a un servidor https a través de un proxy http.
HairOfTheDog
si recibe una solicitud incorrecta,
escriba
9
¿Cómo puedo integrar el usuario proxy y la contraseña proxy en el bloque de opciones?
Twistleton
¿Ha cambiado esto? Incluso con el destino final como otro servidor local, recibo una 404, y el servidor de destino no recibe la solicitud ..
OJFord
53

Puede usar request , acabo de encontrar que es increíblemente fácil usar proxy en node.js, solo con un parámetro "proxy" externo, aún más es compatible con HTTPS a través de un proxy 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);
  }
})
Imskull
fuente
1
Trabajé para ambos httpy httpsen mi caso, muchas gracias
Samuel Bushi
alguna idea de por qué esto no funcionará para las páginas internas del cuerpo?
keinabel
1
Me sorprende que las páginas internas del cuerpo estén detrás de un proxy. ¿Está seguro de que el proxy no se omite para las páginas internas? ¿Está en una vlan diferente?
Chanoch
Necesitas especificar la autenticación de alguna manera (la publicaré aquí si lo descubro)
Igor L.
Recibí este error usando la solicitud con proxy: Error: no se pudo establecer el socket de túnel, causa = conectar ECONNREFUSED 127.0.0.1:80
Federico Caccia
35

Una cosa que me llevó un tiempo descubrir, usar 'http' para acceder al proxy, incluso si está intentando conectarse a un servidor https. Esto funciona para mí usando Charles (analizador de protocolo 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);
});
Chris
fuente
1
El código anterior no funciona para mí, y está relacionado con el problema github.com/joyent/node/issues/2474 verifique la respuesta de koichik, tenemos que usar "método": "conectar" y en el evento "conectar", hemos enviado información de ruta .
Palani
16

Como @Renat ya mencionó aquí, el tráfico HTTP proxy viene en solicitudes HTTP bastante normales. Realice la solicitud contra el proxy, pasando la URL completa del destino como la ruta.

var http = require ('http');

http.get ({
    host: 'my.proxy.com',
    port: 8080,
    path: 'http://nodejs.org/'
}, function (response) {
    console.log (response);
});
Tim Macfarlane
fuente
2
Esto parece funcionar aunque violinista llama una violación de protocolo que sugiere que no es una petición HTTP adecuado-via-proxy ...
Marc
11

Pensé que agregaría este módulo que encontré: https://www.npmjs.org/package/global-tunnel , que funcionó muy bien para mí (funcionó de inmediato con todo mi código y módulos de terceros con solo el código a continuación).

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

Haga esto una vez, y todos los http (y https) en su aplicación pasan por el proxy.

Alternativamente, llamando

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

Utilizará la http_proxyvariable de entorno.

Major Mann
fuente
2
¡Esto funcionó para mí! De hecho, de esta manera desacoplas el proxy del código y usas la configuración existente para npm. ese es el camino a seguir, diría
cesaregb
@NeelBasu Sí lo hace
major-mann
10

Compré un servidor proxy privado, después de la compra obtuve:

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

Y quería usarlo. La primera respuesta y la segunda respuesta solo funcionaron para http (proxy) -> http (destino), sin embargo, quería http (proxy) -> https (destino).

Y para el destino https, sería mejor usar el túnel HTTP directamente. Encontré solución aquí . Código final:

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()
Alexey Volodko
fuente
7

El paquete http 'request' parece tener esta característica:

https://github.com/mikeal/request

Por ejemplo, el objeto de solicitud 'r' a continuación utiliza localproxy para acceder a sus solicitudes:

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)
  }
})

Desafortunadamente, no hay valores predeterminados "globales", por lo que los usuarios de las bibliotecas que usan esto no pueden modificar el proxy a menos que la lib pase a través de las opciones http ...

HTH, Chris

Chris Kimpton
fuente
El paquete http de solicitud hace que sea más fácil permitir que su código cambie entre el uso proxy y el no proxy (lo cual es bastante útil en mi computadora portátil).
Jon Madison
5

Básicamente no necesita un soporte de proxy explícito. El protocolo proxy es bastante simple y se basa en el protocolo HTTP normal. Solo necesita usar su host proxy y puerto cuando se conecta con HTTPClient. Ejemplo (de los documentos de 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();
...

Así que básicamente te conectas a tu proxy pero haces una solicitud a "http://www.google.com".

Renat
fuente
3
http.createClient está en desuso, Tim Macfarlane está utilizando el http.get más nuevo a continuación
sami
1
Aparentemente, esto ya no funcionará con node.js a partir de v5.6, ya que han eliminado createClient .
Marc
5

En caso de que necesite utilizar la autorización básica para su proveedor proxy, solo use lo siguiente:

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();
Vyacheslav Voronchuk
fuente
1
¿Dónde puedo encontrar "FarmerAdapter"?
Alex
3

Node debe admitir el uso de la variable de entorno http_proxy, por lo que es multiplataforma y funciona en la configuración del sistema en lugar de requerir una configuración por aplicación.

Usando las soluciones proporcionadas, recomendaría lo siguiente:

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);
};

Uso Para usar el método, simplemente reemplace http.get, por ejemplo, lo siguiente escribe la página de índice de google en un archivo llamado 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"
Luke
fuente
Establecer http_proxy no parece tener ningún efecto al ejecutar Node en Windows.
EricLaw
Debería funcionar en Windows (ese es el sistema principal que estoy usando). Asegúrese de que después de haber configurado la configuración, haya restablecido su sesión de terminal (si se configuró a través del panel de control y no se configuró). Debería poder verificar que esté configurado correctamente usando echo% HTTP_PROXY% O incluso mejor, debería usar el nodo en sí node -e "console.log (process.env.http_proxy);" Esto funcionó para mí en Windows, así que buena suerte.
Lucas
1

La respuesta de Imskull casi funcionó para mí, pero tuve que hacer algunos cambios. El único cambio real es agregar nombre de usuario, contraseña y establecer el rechazo No autorizado en falso. No podía comentar, así que puse esto en una respuesta.

Si ejecuta el código, obtendrá los títulos de las historias actuales en Hacker News, según este tutorial: 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.');
    }
});
Vasily Kushakov
fuente
1

Creo que hay una mejor alternativa a las respuestas a partir de 2019. Podemos usar el global-tunnel-ngpaquete para inicializar el proxy y no contaminar el código httpo el httpscódigo basado en todas partes. Así que primero instale el global-tunnel-ngpaquete:

npm install global-tunnel-ng

Luego cambie sus implementaciones para inicializar el proxy si es necesario como:

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

globalTunnel.initialize({
  host: 'proxy.host.name.or.ip',
  port: 8080
});
portador del anillo
fuente
0

Es posible que no sea la línea exacta que esperaba, pero puede echar un vistazo a http://github.com/nodejitsu/node-http-proxy ya que eso puede arrojar algo de luz sobre cómo puede usar su aplicación con http. Cliente.

fullstacklife
fuente
1
¿Cómo es esto útil?
Jerinaw
0

http://groups.google.com/group/nodejs/browse_thread/thread/d5aadbcaa00c3f7/12ebf01d7ec415c3?lnk=gst&q=proxy#12ebf01d7ec415c3

Según las respuestas de este hilo, parece que podría usar proxychains para ejecutar node.js a través del servidor proxy:
$ proxychains /path/to/node application.js

Personalmente, no pude instalar ninguna de las versiones de proxychains en el entorno Cygwin / Windows , por lo que no pude probarlo.

Además, también hablaron sobre el uso de connect-proxy pero no pude encontrar ninguna documentación sobre cómo hacerlo.

En resumen, todavía estoy atascado, pero tal vez alguien pueda usar esta información para encontrar una solución adecuada.

ddallala
fuente
Actualización: después de investigar un poco descubrí que no podía construir cadenas de proxy en CygWin porque RTLD_NEXT no es compatible.
ddallala
0

use 'https-proxy-agent' como este

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)=>{...});
Verde malo
fuente
0

Si tiene el esquema de autenticación HTTP básico, debe crear una cadena base64 myuser:mypasswordy luego agregar "Básico" al principio. Ese es el valor del encabezado Proxy-Authorization , aquí un ejemplo:

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();

En nodejs puedes usar Buffer para codificar

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

console.log(encodedData);

Como ejemplo, en los navegadores puede codificar en base64 usando btoa () , útil en solicitudes ajax en un navegador sin configuraciones de proxy que realicen una solicitud usando proxy.

var encodedData = btoa('myuser:mypassword')

console.log(encodedData);

¿Cómo encontrar qué esquema acepta el servidor proxy?

Si no tenemos un DNS personalizado configurado (que arrojaría algo como ERR_NAME_NOT_RESOLVED), cuando realizamos una solicitud, la respuesta (código 407) debería informar en los encabezados de respuesta qué esquema de autenticación http está usando el proxy.

Emeeus
fuente