How can I use an http proxy with node.js http.Client?

HttpProxynode.js

Http Problem Overview


I want to make an outgoing HTTP call from node.js, using the standard http.Client. But I cannot reach the remote server directly from my network and need to go through a proxy.

How do I tell node.js to use the proxy?

Http Solutions


Solution 1 - Http

Tim Macfarlane's answer was close with regards to using a HTTP proxy.

Using a HTTP proxy (for non secure requests) is very simple. You connect to the proxy and make the request normally except that the path part includes the full url and the host header is set to the host you want to connect to.
Tim was very close with his answer but he missed setting the host header properly.

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

For the record his answer does work with http://nodejs.org/ but that's because their server doesn't care the host header is incorrect.

Solution 2 - Http

EDIT: As of Feb 11th 2020, request is fully deprecated. No new changes are expected.

You can use request, I just found it's unbelievably easy to use proxy on node.js, just with one external "proxy" parameter, even more it supports HTTPS through a http proxy.

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

Solution 3 - Http

One thing that took me a while to figure out, use 'http' to access the proxy, even if you're trying to proxy through to a https server. This works for me using Charles (osx protocol analyser):

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

Solution 4 - Http

I bought private proxy server, after purchase I got:

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

And I wanted to use it. First answer and second answer worked only for http(proxy) -> http(destination), however I wanted http(proxy) -> https(destination).

And for https destination it would be better to use HTTP tunnel directly. I found solution here.

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

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

Solution 5 - Http

As @Renat here already mentioned, proxied HTTP traffic comes in pretty normal HTTP requests. Make the request against the proxy, passing the full URL of the destination as the path.

var http = require ('http');

http.get ({
    host: 'my.proxy.com',
    port: 8080,
    path: 'http://nodejs.org/'
}, function (response) {
    console.log (response);
});

Solution 6 - Http

Thought I would add this module I found: https://www.npmjs.org/package/global-tunnel, which worked great for me (Worked immediately with all my code and third party modules with only the code below).

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

Do this once, and all http (and https) in your application goes through the proxy.

Alternately, calling

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

Will use the http_proxy environment variable

Solution 7 - Http

The 'request' http package seems to have this feature:

https://github.com/mikeal/request

For example, the 'r' request object below uses localproxy to access its requests:

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

Unfortunately there are no "global" defaults so that users of libs that use this cannot amend the proxy unless the lib pass through http options...

HTH, Chris

Solution 8 - Http

In case you need to the use basic authorisation for your proxy provider, just use the following:

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

Solution 9 - Http

Basically you don't need an explicit proxy support. Proxy protocol is pretty simple and based on the normal HTTP protocol. You just need to use your proxy host and port when connecting with HTTPClient. Example (from node.js docs):

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

So basically you connect to your proxy but do a request to "http://www.google.com";.

Solution 10 - Http

Node should support using the http_proxy environmental variable - so it is cross platform and works on system settings rather than requiring a per-application configuration.

Using the provided solutions, I would recommend the following:

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

Usage To use the method, effectively just replace http.get, for instance the following writes the index page of google to a file called 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"

Solution 11 - Http

I think there a better alternative to the answers as of 2019. We can use the global-tunnel-ng package to initialize proxy and not pollute the http or https based code everywhere. So first install global-tunnel-ng package:

npm install global-tunnel-ng

Then change your implementations to initialize proxy if needed as:

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

globalTunnel.initialize({
  host: 'proxy.host.name.or.ip',
  port: 8080
});

Solution 12 - Http

Imskull's answer almost worked for me, but I had to make some changes. The only real change is adding username, password, and setting rejectUnauthorized to false. I couldn't comment so I put this in an answer.

If you run the code it'll get you the titles of the current stories on Hacker News, per this 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.');
    }
});

Solution 13 - Http

Solution 14 - Http

May not be the exact one-liner you were hoping for but you could have a look at http://github.com/nodejitsu/node-http-proxy as that may shed some light on how you can use your app with http.Client.

Solution 15 - Http

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

Based on the answers from this thread it would seem like you could use proxychains to run node.js through the proxy server:
$ proxychains /path/to/node application.js

Personally I wasnt able to install any of the proxychains versions on Cygwin/Windows environment so couldn't test it.

Furthermore, they also talked about using connect-proxy but I could not find any documentation on how to do this.

In short, I'm still stuck, but maybe someone can use this info to find a suitable work-around.

Solution 16 - Http

use 'https-proxy-agent' like this

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)=>{...});

Solution 17 - Http

If you have the Basic http authentication scheme you have to make a base64 string of myuser:mypassword, and then add "Basic" in the beginning. That's the value of Proxy-Authorization header, here an example:

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

In nodejs you could use Buffer to encode

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

console.log(encodedData);

Just as example, in browsers you could encode in base64 using btoa(), useful in ajax requests in a browser without proxy settings performing a request using proxy.

var encodedData = btoa('myuser:mypassword')

console.log(encodedData);

How to find wich scheme accepts the proxy server?

If we don't have a custom DNS configured (that would throw something like ERR_NAME_NOT_RESOLVED), when we perform a request, the response (code 407) should inform in the response headers which http authentication scheme the proxy is using.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChristian BergView Question on Stackoverflow
Solution 1 - HttpSamuelView Answer on Stackoverflow
Solution 2 - HttpImskullView Answer on Stackoverflow
Solution 3 - HttpChrisView Answer on Stackoverflow
Solution 4 - HttpAlexey VolodkoView Answer on Stackoverflow
Solution 5 - HttpTim MacfarlaneView Answer on Stackoverflow
Solution 6 - Httpmajor-mannView Answer on Stackoverflow
Solution 7 - HttpChris KimptonView Answer on Stackoverflow
Solution 8 - HttpVyacheslav VoronchukView Answer on Stackoverflow
Solution 9 - HttpRenatView Answer on Stackoverflow
Solution 10 - HttpLukeView Answer on Stackoverflow
Solution 11 - Httpring bearerView Answer on Stackoverflow
Solution 12 - HttpVasily KushakovView Answer on Stackoverflow
Solution 13 - Httpuser956584View Answer on Stackoverflow
Solution 14 - HttpfullstacklifeView Answer on Stackoverflow
Solution 15 - HttpddallalaView Answer on Stackoverflow
Solution 16 - HttpBad GreenView Answer on Stackoverflow
Solution 17 - HttpEmeeusView Answer on Stackoverflow