Comment puis-je utiliser un proxy http avec node.js http.Client?

137

Je souhaite passer un appel HTTP sortant à partir de node.js, en utilisant le standard http.Client. Mais je ne peux pas accéder au serveur distant directement depuis mon réseau et je dois passer par un proxy.

Comment dire à node.js d'utiliser le proxy?

Christian Berg
la source
1
J'ai le même problème. Node.js est derrière un pare-feu et je suis incapable de créer un HTTPClient sur un site Web externe.
ddallala

Réponses:

153

La réponse de Tim Macfarlane était proche en ce qui concerne l'utilisation d'un proxy HTTP.

L'utilisation d'un proxy HTTP (pour les requêtes non sécurisées) est très simple. Vous vous connectez au proxy et effectuez la demande normalement, sauf que la partie chemin comprend l'URL complète et que l'en-tête d'hôte est défini sur l'hôte auquel vous souhaitez vous connecter.
Tim était très proche de sa réponse mais il a manqué de régler correctement l'en-tête de l'hôte.

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

Pour mémoire, sa réponse fonctionne avec http://nodejs.org/ mais c'est parce que leur serveur ne se soucie pas que l'en-tête d'hôte est incorrect.

Samuel
la source
1
Existe-t-il un moyen d'utiliser le port https de connexion proxy http? semble n'a pas de méthode facile
Gohan
@Gohan Voir la réponse de Chris ci-dessous pour un exemple sur la façon de se connecter à un serveur https via un proxy http.
HairOfTheDog
si vous obtenez une mauvaise requête, mettez le chemin: '/'
Laurent Debricon
9
Comment puis-je intégrer un utilisateur proxy et un mot de passe proxy dans le bloc d'options?
Twistleton
Cela a-t-il changé? Même avec la destination finale comme un autre serveur local, j'obtiens un 404, et le serveur de destination ne reçoit jamais la demande ..
OJFord
53

Vous pouvez utiliser request , je viens de trouver qu'il est incroyablement facile d'utiliser un proxy sur node.js, juste avec un paramètre externe "proxy", encore plus il prend en charge HTTPS via 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
la source
1
A travaillé pour les deux httpet httpsdans mon cas, merci beaucoup
Samuel Bushi
des idées pourquoi cela ne fonctionnera pas pour les pages internes de l'entreprise?
keinabel
1
Je suis surpris que les pages internes de l'entreprise se trouvent derrière un proxy. Êtes-vous sûr que le proxy n'est pas contourné pour les pages internes? Est-ce sur un autre vlan?
Chanoch
Vous devez spécifier l'authentification d'une manière ou d'une autre (je vais le poster ici si je le comprends)
Igor L.
J'ai eu cette erreur en utilisant la demande avec le proxy: Erreur: la prise de tunneling n'a pas pu être établie, cause = connect ECONNREFUSED 127.0.0.1:80
Federico Caccia
35

Une chose qui m'a pris un certain temps à comprendre, utilisez 'http' pour accéder au proxy, même si vous essayez de passer par proxy via un serveur https. Cela fonctionne pour moi en utilisant Charles (analyseur de protocole 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
la source
1
Le code ci-dessus ne fonctionne pas pour moi, et il est lié au problème github.com/joyent/node/issues/2474 Vérifiez la réponse de koichik, nous devons utiliser "method": "connect" et lors de l'événement "connect", nous avons envoyé des informations de chemin .
Palani
16

Comme @Renat l'a déjà mentionné, le trafic HTTP proxy est fourni dans des requêtes HTTP assez normales. Faites la demande auprès du proxy, en passant l' URL complète de la destination comme chemin.

var http = require ('http');

http.get ({
    host: 'my.proxy.com',
    port: 8080,
    path: 'http://nodejs.org/'
}, function (response) {
    console.log (response);
});
Tim Macfarlane
la source
2
Cela semble fonctionner bien que Fiddler l'appelle une violation de protocole, ce qui suggère que ce n'est pas une requête HTTP appropriée via proxy ...
Marc
11

Je pensais ajouter ce module que j'ai trouvé: https://www.npmjs.org/package/global-tunnel , qui a très bien fonctionné pour moi (a travaillé immédiatement avec tout mon code et des modules tiers avec uniquement le code ci-dessous).

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

Faites-le une fois, et tous les http (et https) de votre application passent par le proxy.

Alternativement, appeler

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

Utilisera la http_proxyvariable d'environnement

major-mann
la source
2
Cela a fonctionné pour moi! En fait, de cette façon, vous dissociez le proxy du code et utilisez la configuration existante pour npm! c'est la voie à suivre, je dirais
cesaregb
@NeelBasu Oui, il le fait
major-mann
10

J'ai acheté un serveur proxy privé, après l'achat j'ai obtenu:

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

Et je voulais l'utiliser. La première réponse et la deuxième réponse ne fonctionnaient que pour http (proxy) -> http (destination), mais je voulais http (proxy) -> https (destination).

Et pour la destination https, il serait préférable d'utiliser directement le tunnel HTTP . J'ai trouvé une solution ici . Code 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
la source
7

Le package http 'request' semble avoir cette fonctionnalité:

https://github.com/mikeal/request

Par exemple, l'objet de requête 'r' ci-dessous utilise localproxy pour accéder à ses requêtes:

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

Malheureusement, il n'y a pas de valeurs par défaut "globales", de sorte que les utilisateurs de bibliothèques qui utilisent cela ne peuvent pas modifier le proxy à moins que la bibliothèque ne passe par les options http ...

HTH, Chris

Chris Kimpton
la source
le package request http facilite la permutation de votre code entre l'utilisation proxy et non proxy (ce qui est très utile sur mon ordinateur portable).
Jon Madison
5

En gros, vous n'avez pas besoin d'un support proxy explicite. Le protocole proxy est assez simple et basé sur le protocole HTTP normal. Il vous suffit d'utiliser votre hôte proxy et votre port lors de la connexion avec HTTPClient. Exemple (à partir de la documentation 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();
...

Donc, fondamentalement, vous vous connectez à votre proxy, mais faites une demande à "http://www.google.com".

Renat
la source
3
http.createClient est obsolète, Tim Macfarlane utilise le nouveau http.get ci
sami
1
Cela ne fonctionnera apparemment plus avec node.js à partir de la v5.6 car ils ont supprimé createClient .
Marc
5

Si vous avez besoin de l'autorisation de base pour votre fournisseur de proxy, utilisez simplement ce qui suit:

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
la source
1
où puis-je trouver "FarmerAdapter"?
Alex
3

Node doit prendre en charge l'utilisation de la variable d'environnement http_proxy - c'est donc multiplateforme et fonctionne sur les paramètres du système plutôt que d'exiger une configuration par application.

En utilisant les solutions fournies, je recommanderais ce qui suit:

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

Utilisation Pour utiliser la méthode, remplacez simplement http.get, par exemple, ce qui suit écrit la page d'index de google dans un fichier appelé 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
la source
La définition de http_proxy ne semble pas avoir d'effet lors de l'exécution de Node sous Windows.
EricLaw
Cela devrait fonctionner sous Windows (c'est le système principal que j'utilise). Assurez-vous après avoir défini le paramètre que vous avez réinitialisé votre session de terminal (si défini via le panneau de commande et non défini). Vous devriez pouvoir vérifier qu'il est correctement défini en utilisant echo% HTTP_PROXY% Ou mieux encore, vous devriez utiliser le nœud lui-même node -e "console.log (process.env.http_proxy);" Cela a fonctionné pour moi sous Windows, alors bonne chance.
Luke
1

La réponse d'Imskull a presque fonctionné pour moi, mais j'ai dû faire quelques changements. Le seul vrai changement est l'ajout d'un nom d'utilisateur, d'un mot de passe et de la définition de rejectUnauthorized sur false. Je ne pourrais pas faire de commentaire alors j'ai mis cela dans une réponse.

Si vous exécutez le code, vous obtiendrez les titres des histoires actuelles sur Hacker News, selon ce tutoriel: 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
la source
1

Je pense qu'il existe une meilleure alternative aux réponses à partir de 2019. Nous pouvons utiliser le global-tunnel-ngpackage pour initialiser le proxy et ne pas polluer le code httpou httpsbasé partout. Alors installez d'abord le global-tunnel-ngpackage:

npm install global-tunnel-ng

Modifiez ensuite vos implémentations pour initialiser le proxy si nécessaire comme:

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

globalTunnel.initialize({
  host: 'proxy.host.name.or.ip',
  port: 8080
});
porteur de l'anneau
la source
0

Ce n'est peut-être pas exactement le one-liner que vous espériez, mais vous pouvez jeter un œil à http://github.com/nodejitsu/node-http-proxy car cela peut vous éclairer sur la façon dont vous pouvez utiliser votre application avec http. Client.

fullstacklife
la source
1
En quoi cela est-il utile?
Jerinaw
0

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

Sur la base des réponses de ce fil, il semblerait que vous puissiez utiliser des chaînes de proxy pour exécuter node.js via le serveur proxy:
$ proxychains /path/to/node application.js

Personnellement, je n'ai pas pu installer l'une des versions de la chaîne proxy sur l' environnement Cygwin / Windows et je n'ai donc pas pu le tester.

De plus, ils ont également parlé de l'utilisation de connect-proxy mais je n'ai trouvé aucune documentation sur la façon de procéder.

En bref, je suis toujours bloqué, mais peut-être que quelqu'un peut utiliser cette information pour trouver une solution de rechange appropriée.

ddallala
la source
mise à jour: après quelques recherches, j'ai découvert que je ne pouvais pas créer de chaînes de proxy sur CygWin car RTLD_NEXT n'est pas pris en charge.
ddallala
0

utilisez 'https-proxy-agent' comme ceci

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)=>{...});
Mauvais vert
la source
0

Si vous disposez du schéma d'authentification HTTP de base , vous devez créer une chaîne base64 de myuser:mypassword, puis ajouter «Basic» au début. C'est la valeur de l'en - tête Proxy-Authorization , voici un exemple:

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

Dans nodejs, vous pouvez utiliser Buffer pour encoder

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

console.log(encodedData);

À titre d'exemple, dans les navigateurs, vous pouvez encoder en base64 en utilisant btoa () , utile dans les requêtes ajax dans un navigateur sans paramètres de proxy effectuant une requête en utilisant un proxy.

var encodedData = btoa('myuser:mypassword')

console.log(encodedData);

Comment trouver quel schéma accepte le serveur proxy?

Si nous n'avons pas de DNS personnalisé configuré (qui lèverait quelque chose comme ERR_NAME_NOT_RESOLVED), lorsque nous effectuons une requête, la réponse (code 407) doit indiquer dans les en-têtes de réponse le schéma d'authentification http utilisé par le proxy.

Emeeus
la source