Pages

Saturday, 30 January 2016

Goproxy, 简单灵活的反向代理和静态资源代理

goproxy代理可以实时的让hosts文件的修改生效,而且对hosts文件的配置功能进行了增强,用起来会很有意思,(因为是用go语言写的,所以取名为goproxy)。先说说这个软件的来由:
做web开发的同学难免会碰到线上、线下、预发布、其他环境相互切换的场景,目前有两个方案:
  1. 方案一:直接在浏览器中把url中的域名改成指定环境的ip:port,回车直接访问。不过这个办法是有缺陷的,比如:你的web应用和样式都需要使用线下的环境时,你就不能通过修改浏览器的url来实现了,因为浏览器的url只能指定web应用的环境,html中的js和css还是使用的域名,当然,如果你不嫌麻烦,也可以修改web应用的源码来使js、css资源的域名改成ip:port。这个方式对于频繁切换环境的人来说无疑很痛苦。而且为了测试而修改了源码,在提交代码时,有会把测试代码提交到线上的风险。
  2. 方案二:在hosts文件中配置几套环境,用switchhosts软件来做几个环境的切换,配合firefox的dns flusher插件(点一下这个插件,可以让firefox立刻重新加载hosts文件),可以比较快速的切换环境。而且dns flusher可以实时查看当前的域名访问的ip是哪个。这个方案明显比第一个方案好很多。但是我使用这种方案很长时间,发现firefox打开页面的速度确实不如chrome,对于每天要刷新页面千百次的我,我甚至快忍受不了firefox的那么一点点慢。但是chrome有个致命的弱点,就是没有一个类似dns flusher的软件,让修改后的hosts文件立刻对浏览器生效。这导致喜欢chrome的同学,每次用hosts切换软件切换了域名绑定后,都只能把chrome关掉,然后重新打开,这样才能让修改后的hosts文件立即生效,好在chrome关闭和打开的速度很算过得去(firefox,估计想屎的心都有了)。
好吧,话归正题,我其实是想用chrome和switchhosts软件做到快速的切换环境,于是用golang开发了goproxy。(项目是开源的代码很简单,大家觉得比较麻烦的代码用golang两行就能搞定,详细使用文档请见项目主页:https://bitbucket.org/weager/goproxy)。
为什么要用代理?代理相当于是浏览器和最终的服务器之间的中转站,浏览器如果使用了代理,你就可以控制浏览器打开的所有页面的,既然chrome不能实时的读取hosts文件,那我可以让goproxy实时的读取hosts文件(其实是每次url访问经过goproxy时去检查一下hosts文件是否修改,修改了就reload一下)。这样每次需要切换环境只需要用switchhosts选择一套环境的hosts绑定,然后F5刷新chrome就可以了。其操作步骤比firefox+dns flusher+switchhosts还要少(dns flusher需要点击触发reload hosts文件)。
这只是一个基本的goproxy代理功能,其实goproxy还有更有意思的功能。下面来一一解读:
hosts文件中配置的映射一般都是把多个域名映射到一个ip上,如果把url前面的“http://”去掉的话,hosts里面的映射,其实就是前缀的替换,比如这个hosts配置:
127.0.0.1  www.1688.com
如果一个url去掉http://后为www.1688.com/index.html,那么映射后的url就为127.0.0.1/index.html。试想,如果我本地的环境端口号不是80,而是8080,怎么办?你能在hosts文件中配置成127.0.0.1:8080 www.1688.com吗?如果你用goproxy就可以这么配了。因为goproxy的原理就是一个前缀的替换,他的配置格式和hosts文件本身的格式非常类似,只是做了一点扩展。所以你可以这样配置:
127.0.0.1:8080  www.1688.com   search.china.alibaba.com   list.china.alibaba.com
127.0.0.1:8080/aaa/ddd   www.1688.com   search.china.alibaba.com/ccc   list.china.alibaba.com/bbb
(注意:路径的斜杠是向左的斜杠,不是windows里面的向右的斜杠。)
继续在url上做文章,上面的两行配置都是反向代理,那是不是也可以把静态资源给代理起来呢?goproxy也做到了,你甚至可以这样配置:
D:/workspace/work/style   style.china.alibaba.com/app/search
看到这个简单的配置,你会意识到你装的apache、varnish可以卸掉了吧
既然代理的功能可以自己定制,那功能应该可以再多一点,比如:对某个前缀的url添加或者删除参数。比如下面的配置:
127.0.0.1:8080    www.1688.com     +debug=true   +begin=2    -n=y  -version
110.20.30.41:8080    www.1688.com     +debug=true   +begin=2    -n=y  -version=2
第一行配置的意思是:如果一个url的前缀是“www.1688.com”,那么就给这个url的参数中添加debug=true和begin=2(如果已经有了begin=1,则会被覆盖成begin=2,debug参数也同理),并移除n=y和version参数(无论version的值是什么,被移除的参数在url中时才移除,不在url中则不作修改)
第二行配置与第一行配置的不同是,移除version参数的条件必须是version的值等于2。
这种些看起来很奇特的配置在hosts中显得很另类,好在现在的浏览器对这种他们看不懂的映射配置直接忽略,只读取他们认识的配置,所以你可以在hosts文件中配置正常的和不正常的配置,正常的配置对没有使用代理的浏览器依然有效,不正常的配置则不会影响浏览器的工作。
目前goproxy我自己一直在使用,用得很爽,也有其他人在用,评价是很轻量级,如果你偏爱goproxy的简单强大的配置功能,那么做web开发切换环境时,可以考虑试试goproxy。当然goproxy不仅仅用于chrome,任何浏览器都可以可以配置代理指向goproxy所在机器的ip和端口号(默认是8000端口).
from  http://rongmayisheng.com/post/goproxy-%E7%81%B5%E6%B4%BB%E7%9A%84%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86%E5%92%8C%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E4%BB%A3%E7%90%86
------------

软件下载

goproxy代理下载 (由于bitbucket基本属于半被墙状态,下载功能必须使用代理才能下载,建议大家使用收费代理或者goAgent免费代理) 该软件的开发缘由,请看我的一篇博文Goproxy-灵活的反向代理和静态资源代理
其他下载地址:
  1. windows64位:goproxy-windows-64-0.0.3.exe
  2. windows32位:goproxy-windows-32-0.0.3.exe

软件介绍

  1. Goproxy使用代理的方式来加强hosts文件的配置,对hosts文件的修改实时生效(不需要使用firefox上的dns flusher插件),对hosts文件里正常的配置没有任何影响。
  2. 通过配置hosts文件中的dns映射,可实现自动替换url的前缀,添加或者移除指定的参数
  3. 配合上switchhosts 等hosts dns切换软件,特别适合web开发时让浏览器快速的切换线上、线下、测试环境。(chrome上没有类似firefox上的dnsflusher插件,有了goproxy你就有福了)
  4. Goproxy也可以作为普通的代理软件来代理HTTP请求,或者代理本地静态资源文件(图片、js、css等,可通过简单的配置取代varnish+apache)。
  5. 无需安装,单个exe文件,双击即可运行,跨平台,无额外的配置文件(只需要配置hosts文件即可,当然也可以自行制定配置文件) 直接修改hosts文件,利用丰富的前缀匹配解决线上线下的环境访问的问题。 建议使用傲游等对代理配置很灵活的浏览器(可以仅对某几个域名使用代理)。

使用介绍

启动goproxy时,用如下的方式可以查看帮助
goproxy.exe -help
代理程序的端口号
在浏览器中配置代理时,默认端口号为8000,如果想使用其他端口号,请在启动goproxy的时候,使用-port=xxx启动参数来修改端口号。比如:
goproxy.exe -port=8080
使用指定的DNS文件
推荐直接修改C:\Windows\System32\drivers\etc\hosts,因为现在已经有不少软件能很好的直接这个文件修改,比如switchhosts 如果你不想修改host文件,而使用其他文件来配置DNS映射关系,也可以通过-hosts=C:\\myconfig.conf来指定其他位置的DNS配置文件。比如:
goproxy.exe -hosts=C:\\myconfig.conf
hosts文件配置
hosts文件的配置是为了让goproxy代理程序知道需要对哪些url前缀进行替换,哪些参数需要增删。你可以把hosts文件配置成这样(当然如果你指定的是其他文件,就把dns映射的配置写到你指定的配置文件中,就不需要修改hosts文件了)
127.0.0.1:8080/app/sea www.baidu.com/search/xxx +pageSize=30 -beginPage
D:/workspace/work/style style.china.alibaba.com/app/search
这行配置的每一项意思是:
最终的url路径前缀 用于匹配的url路径前缀 需要添加的参数 需要移除的参数
第一行配置相当于把url中“www.baidu.com/search/xxx”前缀替换为“127.0.0.1:8080/app/sea”,并给替换后的url添加参数pageSize=30,并移除参数beginPage及其参数值。
第二行配置是指把http://style.china.alibaba.com/app/search前缀开头的url替换为D:/workspace/work/style前缀,并读取本地文件返回给浏览器。
当然普通的host dns映射配置和注释都是无缝的支持的,因为操作系统对这些奇怪的配置忽略掉了,对正常的配置仍然是生效的。比如你的chrome配置了代理指向goproxy,那么hosts文件中的所有配置都会有效,而你的firefox没有配置代理,那么firefox会使用hosts中的正常的dns映射,以上奇怪的映射会被忽略,不会影响firefox的正常使用。
hosts文件配置高级用法
goproxy的原理其实很简单,就是替换前缀,增减参数,它是按照配置文件中配置的顺序,从第一条开始匹配,一旦匹配上,就替换前缀得到替换后的新url,然后用新url访问;如果都没匹配上,则对url不做任何修改直接访问。所以如果一个url在hosts映射配置中有两个映射配置都符合时,出现在配置文件前面的会被使用。
D:/workspace/work/style style.china.alibaba.com/app/search
10.20.111.10 style.china.alibaba.com
www.1688.com www.1688.com +debug=true
第一行和第二行有相同的域名,如果url的前缀为style.china.alibaba.com/app/search,则会匹配上第一行的映射,第二行不会被匹配上;如果url的前缀为style.china.alibaba.com\aaa,则会匹配上第二行的映射,匹配后的url为10.20.111.10\aaa。
第三行的配置显得有点奇怪,最终的url路径前缀和用于匹配的url前缀相同,这样做只是为了让www.1688.com前缀的url都加上debug=true的参数而已(匹配上了才会可以增减参数,所以此处是巧妙运用了一下),如果不这样配置,goproxy是不会知道这个url需要加参数的。
from https://bitbucket.org/weager/goproxy/overview
----------------------------------------------------------------------

用一个go脚本实现基于VPN的本地HTTP代理

最近用VPN的时候觉得有些地方不太好用,比如说用HTTP代理的时候可以用Chrome的proxy-switchysharp插件做自动切换,这样访问国内资源时和访问国外资源时都很快。因此我用goproxy写了几行代码做了个可以指定本地出口IP的http proxy,连VPN时去掉“Send all traffic over VPN connection“选项,然后用proxy-switchysharp自动切换出口。
不过现在程序还有一些问题,我尝试去访问facebook和twitter都失败了,不知道为什么,同样是https,google和stackoverflow都是正常的,求高手指点。
好了,我知道为什么脸书和推推不能访问了,因为DNS墙了。。。解析出来的地址就不对。
不知道有没有办法在go里面指定ResolveTCPAddr的dns服务器,我现在只能在hosts文件里面加上正确的IP地址来访问。
代码如下:(把下面的代码保存为proxy.go文件)
package main

import (
    "github.com/elazarl/goproxy"
    "log"
    "net"
    "flag"
    "net/http"
)

var (
    listen = flag.String("listen", "localhost:8080", "listen on address")
    ip = flag.String("ip", "", "listen on address")
    verbose = flag.Bool("verbose", false, "verbose output")
)

func main() {
    flag.Parse()

    if *ip == "" {
        log.Fatal("IP address must be speicified")
    }

    proxy := goproxy.NewProxyHttpServer()
    proxy.Verbose = *verbose
    proxy.Tr.Dial = func (network, addr string) (c net.Conn, err error) {
        if network == "tcp" {
            localAddr, err := net.ResolveTCPAddr(network, *ip + ":0");
            if err != nil {
                return nil, err;
            }
            remoteAddr, err := net.ResolveTCPAddr(network, addr);
            if err != nil {
                return nil, err;
            }
            return net.DialTCP(network, localAddr, remoteAddr);
        }

        return net.Dial(network, addr);
    }
    log.Fatal(http.ListenAndServe(*listen, proxy))
}
使用方法:
go run proxy.go -ip VPN虚拟网卡的IP地址
启动代理之后就可以像普通http代理一样在浏览器中使用他咯,非常方便。
另外看到一个也是基于goproxy的项目,功能也挺有意思,主要是为开发者解决切换开发、生产环境麻烦的问题。有时间的话想整合一下这些功能,但是好像作者已经不更新了,而且是发布在bitbucket的:https://bitbucket.org/weager/goproxy/