【问题标题】:How can I use an http proxy with node.js http.Client?如何将 http 代理与 node.js http.Client 一起使用?
【发布时间】:2011-04-21 05:45:54
【问题描述】:

我想使用标准 http.Client 从 node.js 进行传出 HTTP 调用。但我无法直接从我的网络访问远程服务器,需要通过代理。

如何告诉 node.js 使用代理?

【问题讨论】:

  • 我遇到了同样的问题。 Node.js 位于防火墙后面,我无法为外部网站创建 HTTPClient。

标签: http proxy node.js


【解决方案1】:

Tim Macfarlaneanswer 在使用 HTTP 代理方面非常接近。

使用 HTTP 代理(用于非安全请求)非常简单。您连接到代理并正常发出请求,除了路径部分包含完整的 url 并且主机标头设置为您要连接的主机。
Tim 非常接近他的答案,但他错过了正确设置主机标题。

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/,但那是因为他们的服务器不在乎主机标头不正确。

【讨论】:

  • 有没有办法使用http代理连接https端口?似乎没有简单的方法
  • @Gohan 有关如何通过 http 代理连接到 https 服务器的示例,请参阅下面 Chris 的回答。
  • 如果您收到错误请求,请输入路径:'/'
  • 如何在选项块中集成代理用户和代理密码?
  • 这有改变吗?即使最终目的地是另一台本地服务器,我也得到了404,而目的地服务器永远不会收到请求..
【解决方案2】:

编辑自 2020 年 2 月 11 日起,请求已完全弃用。预计不会有新的变化。

您可以使用request, 我刚刚发现在 node.js 上使用代理非常简单,只需一个外部“代理”参数,它还通过 http 代理支持 HTTPS。

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

【讨论】:

  • 在我的情况下为 httphttps 工作,非常感谢
  • 任何想法为什么这不适用于内部公司页面?
  • 我很惊讶内部公司页面在代理后面。您确定内部页面没有绕过代理吗?它在不同的vlan上吗?
  • 你需要以某种方式指定身份验证(如果我弄明白了就会在这里发布)
  • @IgorL。我让它与 Auth 和请求模块一起使用,headers: {'Proxy-Authorization': XXXX}
【解决方案3】:

我花了一段时间才弄清楚的一件事是,使用“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);
});

【讨论】:

  • 上面的代码对我不起作用,它与问题github.com/joyent/node/issues/2474有关,检查koichik的回答我们必须使用“method”:“connect”和“connect”事件,我们有发送路径信息.
【解决方案4】:

我购买了私人代理服务器,购买后我得到了:

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

我想使用它。 First answersecond answer 仅适用于 http(proxy) -> http(destination),但我想要 http(proxy) -> https(destination)。

对于 https 目标,最好直接使用HTTP tunnel。 我找到了解决方案here

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

【讨论】:

  • socket 属性未在 nodejs 中记录。是否删除了此选项。
  • 所描述的方法现在行不通了。 http 模块的 get / request 函数不支持 socket 选项,因此会被忽略。
【解决方案5】:

正如@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);
});

【讨论】:

  • 这似乎可行,尽管 Fiddler 称其为协议违规,这表明它不是通过代理的正确 HTTP 请求...
【解决方案6】:

我想我会添加这个我发现的模块: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 环境变量

【讨论】:

  • 这对我有用!实际上,通过这种方式,您可以将代理与代码分离,并使用现有的 npm 配置!这就是我想说的方法
  • @NeelBasu 是的
  • 一旦我使用它,应用程序请求不再起作用:登录失败并出现错误 RequestError: Protocol "https:" not supported。预期“未定义”
【解决方案7】:

“请求”http 包似乎有这个功能:

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,克里斯

【讨论】:

  • 请求 http 包使您的代码更容易在代理和非代理使用之间切换(这在我的笔记本电脑上非常有用)。
【解决方案8】:

如果您需要为您的代理提供商使用基本授权,请使用以下内容:

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

【讨论】:

  • 在哪里可以找到“FarmerAdapter”?
【解决方案9】:

基本上,您不需要明确的代理支持。代理协议非常简单,基于普通的 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”发出请求。

【讨论】:

  • http.createClient 已弃用,Tim Macfarlane 正在使用以下较新的 http.get
  • 从 v5.6 开始,这显然不再适用于 node.js,因为它们已删除 createClient
【解决方案10】:

节点应该支持使用 http_proxy 环境变量 - 所以它是跨平台的并且可以在系统设置上工作,而不是需要每个应用程序的配置。

使用提供的解决方案,我会推荐以下内容:

咖啡脚本

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"

【讨论】:

  • 在 Windows 上运行 Node 时,设置 http_proxy 似乎没有任何效果。
  • 它应该可以在 Windows 下工作(这是我使用的主要系统)。确保在设置设置后重置终端会话(如果通过控制面板设置但未设置)。您应该能够使用 echo %HTTP_PROXY% 检查它的设置是否正确,或者更好的是,您应该使用节点本身 node -e "console.log(process.env.http_proxy);"这在 Windows 下对我有用,祝你好运。
【解决方案11】:

我认为截至 2019 年的答案有更好的替代方案。我们可以使用 global-tunnel-ng 包来初始化代理,并且不会到处污染基于 httphttps 的代码。所以先安装global-tunnel-ng包:

npm install global-tunnel-ng

然后根据需要更改您的实现以初始化代理:

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

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

【讨论】:

    【解决方案12】:

    Imskull 的回答几乎对我有用,但我不得不做出一些改变。唯一真正的变化是添加用户名、密码,并将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.');
        }
    });
    

    【讨论】:

      【解决方案13】:

      【讨论】:

        【解决方案14】:

        可能不是您所希望的确切单行,但您可以查看http://github.com/nodejitsu/node-http-proxy,因为这可能会帮助您了解如何将您的应用与 http.Client 一起使用。

        【讨论】:

        • 这有什么帮助?
        【解决方案15】:

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

        根据该线程的答案,您似乎可以使用proxychains 通过代理服务器运行node.js:
        $ proxychains /path/to/node application.js

        我个人无法在 Cygwin/Windows 环境中安装任何 proxychains 版本,因此无法对其进行测试。

        此外,他们还谈到了使用 connect-proxy,但我找不到任何有关如何执行此操作的文档。

        简而言之,我仍然陷入困境,但也许有人可以使用此信息找到合适的解决方法。

        【讨论】:

        • 更新:经过调查发现我无法在 CygWin 上构建代理链,因为不支持 RTLD_NEXT。
        【解决方案16】:

        为了使用带有 https 的代理,我尝试了这个网站上的建议(使用依赖 https-proxy-agent),它对我有用:

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

        【讨论】:

          【解决方案17】:

          像这样使用“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)=>{...});
          

          【讨论】:

            【解决方案18】:

            如果您有Basic http authentication scheme,您必须创建一个myuser:mypassword 的base64 字符串,然后在开头添加“Basic”。这就是Proxy-Authorization header 的值,这里是一个例子:

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

            例如,在浏览器中,您可以使用 btoa() 在 base64 中进行编码,这在没有代理设置的浏览器中使用代理执行请求时非常有用。

            var encodedData = btoa('myuser:mypassword')
            
            console.log(encodedData);

            如何找到接受代理服务器的方案?

            如果我们没有配置自定义 DNS(这会抛出类似 ERR_NAME_NOT_RESOLVED 的东西),当我们执行请求时,响应(代码 407)应在响应标头中告知代理正在使用哪种 http 身份验证方案。

            【讨论】:

              猜你喜欢
              • 2013-05-27
              • 2016-07-16
              • 2019-12-18
              • 2011-07-06
              • 1970-01-01
              • 1970-01-01
              • 2016-10-31
              • 2021-08-21
              • 2016-03-08
              相关资源
              最近更新 更多