用node-http-proxy搭建代理

摘要:
同时,您还可以选择传入选项对象1varhttpProxy=require('httpproxy');使用close〔callback〕函数关闭内部Web服务器并停止侦听给定端口是很方便的。然后,您可以如下调用函数代理来请求1http.createServer(function(req,您也可以添加自己的业务逻辑来处理请求1varhttp=require('http'),

程序员三大必备网站是:Google、Github、StackOverflow。如果你还在用Baidu搜索技术文章的话,我想说的是,少年你已经被鄙视很多年了,赶紧换成谷歌吧,不要再被鄙视了!Github、StackOverflow在国内能够正常访问,但是Google由于众所周知的原因,国内无法访问,所以我们需要FQ访问Google。个人觉得shadowsocks的是目前最好用的代理,没有之一!shadowsocks有多牛?前段时间shadowsocks的作者被约谈了,还被要求删除在Github上的源码,你说有多牛!可以自己在vps上利用shadowsocks搭建自己的专属代理,如果你懒的话,也可以直接去买个shadowsocks账号,网上卖家多的是。后面我会写相关的文章介绍如何在vps上搭建服务器,敬请关注。今天先介绍一下用node-http-proxy搭建谷歌代理,小试牛刀一下。

node-http-proxy是一个用于Node.js的HTTP可编程代理库,支持 websockets。它是适用于实现例如代理服务器和负载均衡这样的组件。node-http-proxy使用起来很简单,下面简单介绍一下。

核心概念

通过createProxyServer函数创建代理,同时你也可选的传入options对象

1 var httpProxy = require('http-proxy');
2 var proxy = httpProxy.createProxyServer(options);

createProxyServer函数返回的proxy对象包含四个方法

  • web req, res, [options] 用来代理http(s)请求
  • ws req, socket, head, [options] 用来代理WS(S)请求
  • listen port 该函数把对象包装成webserver,方便使用
  • close [callback] 该函数关闭内部的webserver并且停止监听给定的端口

然后可以如下调用函数代理请求

1 http.createServer(function(req, res) {
2   proxy.web(req, res, { target: 'http://mytarget.com:8080' });
3 });

错误处理可以通过监听error事件

1 proxy.on('error', function(e) {
2   ...
3 });

或者使用回调API

1 proxy.web(req, res, { target: 'http://mytarget.com:8080' }, function(e) { ... });

Use Cases

下面的例子显示如何用你自己的http服务器代理请求,你也可以加入自己的业务逻辑处理请求

 1 var http = require('http'),
 2     httpProxy = require('http-proxy');
 3 
 4 //
 5 // Create a proxy server with custom application logic
 6 //
 7 var proxy = httpProxy.createProxyServer({});
 8 
 9 //
10 // Create your custom server and just call `proxy.web()` to proxy
11 // a web request to the target passed in the options
12 // also you can use `proxy.ws()` to proxy a websockets request
13 //
14 var server = http.createServer(function(req, res) {
15   // You can define here your custom logic to handle the request
16   // and then proxy the request.
17   proxy.web(req, res, { target: 'http://127.0.0.1:5060' });
18 });
19 
20 console.log("listening on port 5050")
21 server.listen(5050);

更多例子请查看官方文档

Options

httpProxy.createProxyServer支持下列options:

  • target: url字符串
  • forward: url字符串
  • agent: 传给http(s).request的对象
  • ssl: 密钥,HTTPS使用
  • ws: true/false, 是否代理websockets
  • xfwd: true/false, 是否加上x-forward头字段
  • secure: true/false, 是否校验ssl证书
  • toProxy: 传递绝对URL作为path
  • prependPath: true/false, 默认值为true,是否在proxy path前面加上target的path
  • ignorePath: true/false, 默认值为false,是否忽略传入的请求的proxy path
  • localAddress: 本地地址
  • changeOrigin: true/false, 默认值为false, 是否更改原始的host头字段为target URL
  • auth: 基本身份认证,比如:‘用户名:密码’来计算Authorization header
  • hostRewrite: 重写重定向(301/302/307/308)的location hostname
  • autoRewrite: 是否自动重写重定向(301/302/307/308)的location host/port,默认值为false
  • protocolRewrite: 重写重定向(301/302/307/308)的location的协议,http或者https,默认值为null

谷歌代理

 1 'use strict';
 2 
 3 var http = require('http');
 4 var https = require('https');
 5 var httpProxy = require('http-proxy');
 6 var url = require('url');
 7 
 8 var PROXY_PORT = 8000;
 9 var proxy, server;
10 
11 // Create a proxy server with custom application logic
12 proxy = httpProxy.createProxy({});
13 
14 proxy.on('error', function (err) {
15     console.log('ERROR');
16     console.log(err);
17 });
18 
19 server = http.createServer(function (req, res) {
20     //var finalUrl = req.url,
21     var finalUrl = 'https://www.google.com';
22     var finalAgent = null;
23     var parsedUrl = url.parse(finalUrl);
24 
25     if (parsedUrl.protocol === 'https:') {
26         finalAgent = https.globalAgent;
27     } else {
28         finalAgent = http.globalAgent;
29     }
30 
31     proxy.web(req, res, {
32         target: finalUrl,
33         agent: finalAgent,
34         headers: { host: parsedUrl.hostname },
35         prependPath: false,
36         xfwd : true,
37         hostRewrite: finalUrl.host,
38         protocolRewrite: parsedUrl.protocol
39     });
40 });
41 
42 console.log('listening on port ' + PROXY_PORT);
43 server.listen(PROXY_PORT);

你没看错,就是这么点代码就能代理谷歌了,前提是你要有个墙外的vps哈!首先设置浏览器的http代理为你的vps,然后再vps上运行上面的代理程序,最后在浏览器中访问www.google.com,然后就是见证奇迹的时候了。有些小伙伴可能迫不及待的拿去试了试,结果发现博主骗人,根本不能代理谷歌。别急,这是因为node-http-proxy有一个小小的bug,不能怪博主,博主也是受害者之一。博主开始也卡在这里很久,最后去阅读源代码才发现问题所在!在node-http-proxy的web-outgoing.js里有个setRedirectHostRewrite函数,该函数的功能就是重定向时重写header中location的host地址,函数代码如下:

 1 function setRedirectHostRewrite(req, res, proxyRes, options) {
 2     if ((options.hostRewrite || options.autoRewrite || options.protocolRewrite)
 3         && proxyRes.headers['location']
 4         && redirectRegex.test(proxyRes.statusCode)) {
 5       var target = url.parse(options.target);
 6       var u = url.parse(proxyRes.headers['location']);
 7 
 8       // make sure the redirected host matches the target host before rewriting
 9       if (target.host != u.host) {
10         return;
11       }
12 
13       if (options.hostRewrite) {
14         u.host = options.hostRewrite;
15       } else if (options.autoRewrite) {
16         u.host = req.headers['host'];
17       }
18       if (options.protocolRewrite) {
19         u.protocol = options.protocolRewrite;
20       }
21 
22       proxyRes.headers['location'] = u.format();
23     }
24   }

问题出在以下代码:

1 // make sure the redirected host matches the target host before rewriting
2      if (target.host != u.host) {
3         return;
4       }

作者的意图是确保重定向的host跟target的host的匹配,不匹配就直接返回。代理谷歌时就会发生不匹配的情况直接返回了。 
比如,博主来自中国,当我curl www.google.com时会重定向到www.google.com.hk:

1 [root@iZu1fmzgm3iZ ~]# curl www.google.com
2 <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
3 <TITLE>302 Moved</TITLE></HEAD><BODY>
4 <H1>302 Moved</H1>
5 The document has moved
6 <A HREF="http://www.google.com.hk/url?sa=p&amp;hl=zh-CN&amp;pref=hkredirect&amp;pval=yes&amp;q=http://www.google.com.hk/%3Fgws_rd%3Dcr&amp;ust=1448378903186576&amp;usg=AFQjCNHtMfRNndvgHHMAzipRzC9NpycwGw">here</A>.
7 </BODY></HTML>

如果你来自日本,当你curl www.google.com时会重定向到www.google.co.jp:

1 [ec2-user@ip-172-31-27-165 ~]$ curl www.google.com
2 <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
3 <TITLE>302 Moved</TITLE></HEAD><BODY>
4 <H1>302 Moved</H1>
5 The document has moved
6 <A HREF="http://www.google.co.jp/?gfe_rd=cr&amp;ei=toJUVubpIcem8wfGirqQDw">here</A>.
7 </BODY></HTML>

因为重定向的host跟target的host不匹配,程序直接返回,hostRewrite无效,所以我们应该去掉以下代码:

1 // make sure the redirected host matches the target host before rewriting
2      if (target.host != u.host) {
3         return;
4       }

当我们注释掉以上代码,重新运行程序,发现已经可以上谷歌了,是不是很神奇!

免责声明:文章转载自《用node-http-proxy搭建代理》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Cobalt Strike使用的一些技巧谷粒商城单点登录(三十七)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

易优CMS:arclist 文档列表

arclist 文档列表(配合arcpagelist标签可实现ajax瀑布流分页)  [基础用法] 名称:arclist 功能:获取系统主从表模型(如:文章、软件、图集、产品等)的一列文档,也称自由列表块标记。 语法: {eyou:arclist typeid='栏目ID' limit='0,10' flag='c' titlelen='30' infol...

Python使用pip安装matplotlib模块

matplotlib是python中强大的画图模块。 首先确保已经安装python,然后用pip来安装matplotlib模块。 进入到cmd窗口下,建议执行python -m pip install -U pip setuptools进行升级。 接着键入python -m pip install matplotlib进行自动的安装,系统会自动下载安装包...

Django 语法笔记

Django 语法创建项目框架 django-admin startproject 项目名 创建子app 业务分化,可以优化团队合作,可以明确找锅 python manage.py startapp 子app名 启动项目 python manage.py runserver 项目目录结构 __init__.py: 声明当前文件夹为一个可导入的包 se...

用Socket开发的一枚小型实时通信App

Socket 英文原意是插座。 在网络世界里, 当一台主机温柔而体贴的同时提供多个服务时, 每个服务被绑定在一个端口上, 而每个端口就好像一个小插座。 用户们连接对应的插座去获取相应的服务。 在Node.js中,使用的是socket.io来实现Realtime的通信。 当程序两端实现数据通信时, 每一端便化身为一枚可爱的Socket了。 本示例使用Expr...

js 动态创建a href 循环下载文件只能下载10个或者固定数目的问题

在web前端项目中,很多地方的下载单张图片/文件都可以用<a href="http://t.zoukankan.com/images/logo.png" download="文件名">来下载指定文件 遇到的问题: 在下载多个文件的时候 使用for 循环来触发 a href  download  (此批量下载方法当然不推荐 很lowB 也体验不好...

nginx配置反向代理示例

环境: nginx1:192.168.68.41 tomcat1:192.168.68.43 tomcat2:192.168.68.45 nginx安装网上很多教程,我是用yum安装的。 配置nginx: vim /etc/nginx/conf.d/default.conf  内容: #负责压缩数据流 gzip on; g...