Jak mogę używać proxy HTTP z http.Client node.js?

137

Chcę wykonać wychodzące połączenie HTTP z node.js, używając standardu http.Client. Ale nie mogę połączyć się ze zdalnym serwerem bezpośrednio z mojej sieci i muszę przejść przez serwer proxy.

Jak powiedzieć node.js, aby używał proxy?

Christian Berg
źródło
1
Mam ten sam problem. Node.js jest za zaporą ogniową i nie mogę utworzyć klienta HTTP dla zewnętrznej witryny internetowej.
ddallala

Odpowiedzi:

153

Tim Macfarlane „s odpowiedź była blisko w odniesieniu do korzystania z serwera proxy HTTP.

Korzystanie z serwera proxy HTTP (w przypadku niezabezpieczonych żądań) jest bardzo proste. Łączysz się z serwerem proxy i wysyłasz żądanie normalnie, z tym wyjątkiem, że część ścieżki zawiera pełny adres URL, a nagłówek hosta jest ustawiony na hosta, z którym chcesz się połączyć.
Tim był bardzo blisko swojej odpowiedzi, ale przegapił prawidłowe ustawienie nagłówka hosta.

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

Dla przypomnienia, jego odpowiedź działa z http://nodejs.org/, ale to dlatego, że ich serwer nie dba o to, że nagłówek hosta jest nieprawidłowy.

Samuel
źródło
1
Czy istnieje sposób korzystania z portu HTTPS połączenia proxy HTTP? wydaje się, że nie ma łatwej metody
Gohan
@Gohan Zobacz odpowiedź Chrisa poniżej, aby zobaczyć przykład połączenia z serwerem https za pośrednictwem serwera proxy http.
HairOfTheDog,
jeśli otrzymasz złe żądanie, umieść ścieżkę: „/”
Laurent Debricon
9
Jak mogę zintegrować użytkownika proxy i hasło proxy w bloku opcji?
Twistleton
Czy to się zmieniło? Nawet jeśli ostateczne miejsce docelowe jest innym lokalnym serwerem, otrzymuję a 404, a serwer docelowy nigdy nie otrzymuje żądania.
OJFord
53

Możesz użyć request , właśnie odkryłem, że jest niewiarygodnie łatwy w użyciu proxy na node.js, tylko z jednym zewnętrznym parametrem "proxy", a nawet bardziej obsługuje HTTPS przez 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
źródło
1
Pracował dla obu httpi httpsw moim przypadku, wielkie dzięki
Samuel Bushi
jakieś pomysły, dlaczego to nie zadziała na wewnętrznych stronach firmowych?
keinabel
1
Dziwię się, że wewnętrzne strony firmowe znajdują się za proxy. Czy jesteś pewien, że serwer proxy nie jest pomijany w przypadku stron wewnętrznych? Czy jest na innej sieci VLAN?
Chanoch,
Musisz jakoś określić uwierzytelnianie (wyślę to tutaj, jeśli to rozgryzę)
Igor L.
Otrzymałem ten błąd, używając żądania z proxy: Błąd: nie można ustanowić gniazda tunelowania, przyczyna = połączenie ECONNREFUSED 127.0.0.1:80
Federico Caccia
35

Jedna rzecz, której zrozumienie zajęło mi trochę czasu, użyj „http”, aby uzyskać dostęp do serwera proxy, nawet jeśli próbujesz połączyć się z serwerem https. To działa dla mnie przy użyciu Charlesa (analizator protokołu 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
źródło
1
Powyższy kod u mnie nie działa, a jest to związane z problemem github.com/joyent/node/issues/2474 sprawdź odpowiedź koichika musimy użyć "metoda": "connect" i na zdarzeniu "connect" wysłaliśmy informację o ścieżce .
Palani
16

Jak już wspomniał @Renat, przez proxy ruch HTTP przychodzi w całkiem normalnych żądaniach HTTP. Prześlij żądanie do serwera proxy, przekazując jako ścieżkę pełny adres URL miejsca docelowego.

var http = require ('http');

http.get ({
    host: 'my.proxy.com',
    port: 8080,
    path: 'http://nodejs.org/'
}, function (response) {
    console.log (response);
});
Tim Macfarlane
źródło
2
Wydaje się, że to działa, chociaż Fiddler nazywa to naruszeniem protokołu, co sugeruje, że nie jest to właściwe żądanie HTTP przez proxy ...
Marc
11

Pomyślałem, że dodam ten moduł, który znalazłem: https://www.npmjs.org/package/global-tunnel , który działał świetnie dla mnie (działał natychmiast z całym moim kodem i modułami stron trzecich tylko z kodem poniżej).

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

Zrób to raz, a wszystkie adresy http (i https) w Twojej aplikacji będą przechodzić przez serwer proxy.

Alternatywnie dzwonię

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

Użyje http_proxy zmiennej środowiskowej

major-mann
źródło
2
To zadziałało dla mnie! Właściwie w ten sposób odłączasz proxy od kodu i używasz istniejącej konfiguracji npm! to jest droga, powiedziałbym
cesaregb
@NeelBasu Tak, tak
major-mann
9

Kupiłem prywatny serwer proxy, po zakupie otrzymałem:

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

I chciałem to wykorzystać. Pierwsza odpowiedź i druga odpowiedź działały tylko dla http (proxy) -> http (miejsce docelowe), jednak chciałem http (proxy) -> https (miejsce docelowe).

A w przypadku miejsca docelowego https lepiej byłoby bezpośrednio użyć tunelu HTTP . Tutaj znalazłem rozwiązanie . Kod końcowy:

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
źródło
7

Wydaje się, że pakiet HTTP „request” ma tę funkcję:

https://github.com/mikeal/request

Na przykład poniższy obiekt żądania `` r '' używa lokalnego serwera proxy, aby uzyskać dostęp do swoich żądań:

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

Niestety nie ma "globalnych" wartości domyślnych, więc użytkownicy bibliotek korzystających z tego nie mogą zmieniać proxy, chyba że biblioteka przejdzie przez opcje http ...

HTH, Chris

Chris Kimpton
źródło
pakiet request http ułatwia zezwalanie kodowi na przełączanie się między używaniem proxy i nie proxy (co jest całkiem przydatne na moim laptopie).
Jon Madison
5

Zasadniczo nie potrzebujesz jawnej obsługi proxy. Protokół proxy jest dość prosty i oparty na normalnym protokole HTTP. Wystarczy użyć hosta proxy i portu podczas łączenia się z HTTPClient. Przykład (z dokumentacji 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();
...

Zasadniczo łączysz się z serwerem proxy, ale wysyłasz żądanie do „http://www.google.com”.

Renat
źródło
3
http.createClient jest przestarzały, Tim Macfarlane używa nowszego http.get poniżej
sami
1
Najwyraźniej nie będzie to już działać z node.js od wersji 5.6, ponieważ usunęli createClient .
Marc
5

W przypadku, gdy potrzebujesz podstawowej autoryzacji dla swojego dostawcy proxy, użyj następujących:

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();
Wiaczesław Woronczuk
źródło
1
gdzie mogę znaleźć „FarmerAdapter”?
Alex
3

Węzeł powinien obsługiwać zmienną środowiskową http_proxy - jest więc wieloplatformowy i działa na ustawieniach systemu, a nie wymaga konfiguracji na aplikację.

Korzystając z dostarczonych rozwiązań, polecam:

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

Użycie Aby skorzystać z tej metody, efektywnie wystarczy zamienić http.get, na przykład poniższy zapis zapisuje stronę indeksową google do pliku o nazwie 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"
Łukasz
źródło
Wydaje się, że ustawienie http_proxy nie ma żadnego wpływu podczas uruchamiania Node w systemie Windows.
EricLaw,
Powinien działać pod Windows (to jest podstawowy system, którego używam). Upewnij się, że po ustawieniu ustawienia zresetowałeś sesję terminala (jeśli została ustawiona za pośrednictwem panelu sterowania i nie została ustawiona). Powinieneś być w stanie sprawdzić, czy jest poprawnie ustawiony za pomocą echo% HTTP_PROXY% Lub jeszcze lepiej powinieneś użyć samego węzła node -e "console.log (process.env.http_proxy);" To działało dla mnie pod Windows, więc powodzenia.
Łukasz
1

Odpowiedź Imskulla prawie mi pomogła, ale musiałem wprowadzić pewne zmiany. Jedyną prawdziwą zmianą jest dodanie nazwy użytkownika, hasła i ustawienia odrzucenia na fałsz. Nie mogłem komentować, więc umieściłem to w odpowiedzi.

Jeśli uruchomisz kod, otrzymasz tytuły aktualnych artykułów w Hacker News, zgodnie z tym samouczkiem: 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.');
    }
});
Wasilij Kushakov
źródło
1

Myślę, że istnieje lepsza alternatywa dla odpowiedzi z 2019 roku. Możemy użyć global-tunnel-ngpakietu do zainicjowania proxy i nie zanieczyszczać kodu httplub httpsopartego na nim wszędzie. Więc najpierw zainstaluj global-tunnel-ngpakiet:

npm install global-tunnel-ng

Następnie zmień swoje implementacje, aby w razie potrzeby zainicjować serwer proxy, tak jak:

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

globalTunnel.initialize({
  host: 'proxy.host.name.or.ip',
  port: 8080
});
posiadacz pierścienia
źródło
0

Może nie być dokładnie tym, na co liczyłeś, ale możesz rzucić okiem na http://github.com/nodejitsu/node-http-proxy, ponieważ może to rzucić trochę światła na sposób korzystania z aplikacji z protokołem http. Klient.

fullstacklife
źródło
1
Jak to jest pomocne?
Jerinaw
0

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

Na podstawie odpowiedzi z tego wątku wydaje się, że możesz użyć proxychains do uruchomienia node.js przez serwer proxy:
$ proxychains /path/to/node application.js

Osobiście nie byłem w stanie zainstalować żadnej wersji proxychains w środowisku Cygwin / Windows, więc nie mogłem tego przetestować.

Co więcej, rozmawiali również o używaniu connect-proxy, ale nie mogłem znaleźć żadnej dokumentacji, jak to zrobić.

Krótko mówiąc, nadal utknąłem, ale może ktoś może wykorzystać te informacje, aby znaleźć odpowiednie obejście.

ddallala
źródło
aktualizacja: po pewnym dochodzeniu okazało się, że nie mogę zbudować łańcuchów proxy na CygWin, ponieważ RTLD_NEXT nie jest obsługiwany.
ddallala
0

użyj „https-proxy-agent” w ten sposób

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)=>{...});
Zły zielony
źródło
0

Jeśli masz podstawowy schemat uwierzytelniania HTTP, musisz utworzyć ciąg base64 myuser:mypassword, a następnie dodać na początku „Basic”. To wartość nagłówka Proxy-Authorization , tutaj przykład:

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

W nodejs możesz użyć bufora do kodowania

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

console.log(encodedData);

Na przykład w przeglądarkach można kodować w base64 za pomocą btoa () , przydatne w żądaniach ajax w przeglądarce bez ustawień proxy, wykonując żądanie za pomocą proxy.

var encodedData = btoa('myuser:mypassword')

console.log(encodedData);

Jak znaleźć schemat, który akceptuje serwer proxy?

Jeśli nie mamy skonfigurowanego niestandardowego DNS (który wyrzuciłby coś takiego jak ERR_NAME_NOT_RESOLVED), kiedy wykonujemy żądanie, odpowiedź (kod 407) powinna informować w nagłówkach odpowiedzi, którego schematu uwierzytelniania http używa proxy.

Emeeus
źródło