不知道怎么取这个名字。
其本身的作用类似一个做负载均衡的反向圈圈。 这个圈圈的作用是根据请求的地址将请求发送到下一个(不同)的圈圈服务器。
在当前的测试中, 尚无法走推犆,脸数之流的https.
检查net/http的代码, 其中连接是通过http.Transport这个结构出去的.
type Transport struct {
// ...省略
// Proxy specifies a function to return a proxy for a given
// Request. If the function returns a non-nil error, the
// request is aborted with the provided error.
//
// The proxy type is determined by the URL scheme. "http"
// and "socks5" are supported. If the scheme is empty,
// "http" is assumed.
//
// If Proxy is nil or returns a nil *URL, no proxy is used.
Proxy func(*Request) (*url.URL, error)
// ...省略
通常设置圈圈的圈圈的代码如下:
proxy.Tr.Proxy = http.ProxyURL(proxyUrl)
这个http.ProxyURL的代码如下:
// ProxyURL returns a proxy function (for use in a Transport)
// that always returns the same URL.
func ProxyURL(fixedURL *url.URL) func(*Request) (*url.URL, error) {
return func(*Request) (*url.URL, error) {
return fixedURL, nil
}
}
根据请求的request来给出圈圈的地址。 这正是我们想要的。
func (t *Transport) connectMethodForRequest(treq *transportRequest) (cm connectMethod, err error) {
if port := treq.URL.Port(); !validPort(port) {
return cm, fmt.Errorf("invalid URL port %q", port)
}
cm.targetScheme = treq.URL.Scheme
cm.targetAddr = canonicalAddr(treq.URL)
if t.Proxy != nil {
cm.proxyURL, err = t.Proxy(treq.Request)
if err == nil && cm.proxyURL != nil {
if port := cm.proxyURL.Port(); !validPort(port) {
return cm, fmt.Errorf("invalid proxy URL port %q", port)
}
}
}
return cm, err
}
如果cm.proxyURL非空才做圈圈的操作。 所以我们可以选择不使用圈圈。
所以完整代码如下, 非常简单:
package main
import (
"flag"
"log"
"net/http"
"net/url"
"strings"
"github.com/elazarl/goproxy"
)
var (
addr = flag.String("addr", ":8080", "proxy listen address")
verbose = flag.Bool("v", false, "should every proxy request be logged to stdout")
vvb2 = flag.Bool("mas", false, "verbose more")
)
const (
NarrowProxyLink = "http://abc:xyz@myvnc:30000"
WideProxyLink = "http://mas:more@192.168.1.3:8080"
)
func init() {
flag.Parse()
}
func makeBi(internal, external *url.URL) func(*http.Request) (*url.URL, error) {
return func(req *http.Request) (*url.URL, error) {
hostname := req.URL.Hostname()
switch {
case hostname == "localhost":
if *vvb2 {
log.Printf("no proxy for localhost")
}
return nil, nil
case strings.HasSuffix(req.URL.Hostname(), "csdn.net"):
if *vvb2 {
log.Printf("using internal:<%v>", req.URL.Hostname())
}
return internal, nil
default:
if *vvb2 {
log.Printf("using external for:<%v>", req.URL.Hostname())
}
return external, nil
}
}
}
func main() {
log.SetFlags(log.Lshortfile)
proxy := goproxy.NewProxyHttpServer()
proxy.Verbose = *verbose
proxyI, err := url.Parse(NarrowProxyLink)
if err != nil {
panic(err)
}
proxyE, err := url.Parse(WideProxyLink)
if err != nil {
panic(err)
}
//log.Printf("Using proxy <%v>", proxyUrl)
//proxy.Tr.Proxy = http.ProxyURL(proxyUrl)
proxy.Tr.Proxy = makeBi(proxyI, proxyE)
log.Fatal(http.ListenAndServe(*addr, proxy))
}
要加上适当的证书才能让浏览器通过这样的代理。
现在暂时不知道如何设置这些证书以及如何正确导出导入。
setCA(caCert(), caKey())
proxy := goproxy.NewProxyHttpServer()
proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm)
参考链接(证书)
https://stackoverflow.com/questions/10175812/how-to-create-a-self-signed-certificate-with-openssl
https://github.com/yuanliangding/books/blob/master/%E8%AE%A1%E7%AE%97%E6%9C%BA%E2%97%8F%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%97%8F%E9%80%9A%E4%BF%A1%E5%8D%8F%E8%AE%AE/HTTP%E6%9D%83%E5%A8%81%E6%8C%87%E5%8D%97%EF%BC%88%E4%B8%AD%E6%96%87%E7%89%88%EF%BC%89.pdf
(HTTP权威指南PDF版本)