go库中自带的反向代理功能和内网代理

idwtwt · · 5804 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

先看反向代理库

type ReverseProxy struct {
	// Director must be a function which modifies
	// the request into a new request to be sent
	// using Transport. Its response is then copied
	// back to the original client unmodified.
	Director func(*http.Request)

	// The transport used to perform proxy requests.
	// If nil, http.DefaultTransport is used.
	Transport http.RoundTripper

	// FlushInterval specifies the flush interval
	// to flush to the client while copying the
	// response body.
	// If zero, no periodic flushing is done.
	FlushInterval time.Duration

	// ErrorLog specifies an optional logger for errors
	// that occur when attempting to proxy the request.
	// If nil, logging goes to os.Stderr via the log package's
	// standard logger.
	ErrorLog *log.Logger

	// BufferPool optionally specifies a buffer pool to
	// get byte slices for use by io.CopyBuffer when
	// copying HTTP response bodies.
	BufferPool BufferPool
}
接着我们看一个例子(网上拷的)

package main

import (
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
)

type handle struct {
	host string
	port string
}

func (this *handle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	remote, err := url.Parse("http://" + this.host + ":" + this.port)
	if err != nil {
		panic(err)
	}
	proxy := httputil.NewSingleHostReverseProxy(remote)
	proxy.ServeHTTP(w, r)
}

func startServer() {
	//被代理的服务器host和port
	h := &handle{host: "127.0.0.1", port: "80"}
	err := http.ListenAndServe(":8888", h)
	if err != nil {
		log.Fatalln("ListenAndServe: ", err)
	}
}

func main() {
	startServer()
}

使用起来很简单。但是我有时有一种特殊需求。如内网代理(想访问的目标服务器在内网),那该如何办呢?一般方向代理是代理服务器可以主动访问目标服务器的,现在目标服务器在内网,代理服务器不能主动去访问目标服务器。通常我们的代理服务器在公网(对于客户和目标服务器),我们让内网的目标服务器先主动与代理服务器建立一个连接,当客户需要经过代理服务器访问目标内网服务器时,再将请求经过内网服务器与代理服务器预先建立的连接发送到内网服务器。

我们有两个服务程序,一个运行在代理服务器,一个运行在内网服务器。

将上面代码稍微改造就成为运行在代理服务器的程序:

package main

import (
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
)
var conn
type handle struct {

}

func (this *handle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
		remote, err := url.Parse("http://127.0.0.1:443")
		if err != nil {
			panic(err)
		}
		proxy := httputil.NewSingleHostReverseProxy(remote)
		var pTransport http.RoundTripper = &http.Transport{
			Proxy:                 http.ProxyFromEnvironment,
			Dial:                  Dial,
			TLSHandshakeTimeout:   10 * time.Second,
			ExpectContinueTimeout: 1 * time.Second,
		}
		proxy.Transport = pTransport

		proxy.ServeHTTP(w,r)
}

func startServer() {
//接受内网服务器主动连接8088端口
l, err := net.Listen("tcp", "0.0.0.0:8088")
	if err != nil {
	
		return 
	}

	go func() {
		
		for {
			conn, err = l.Accept() //循环接受客户端和设备的连接请求
			if err != nil {
				beego.Error("Can't Accept: ", err)
				return
			}
		
		}

	}()


	//接受客户端的连接
	h := &handle{}
	err := http.ListenAndServe(":8888", h)
	if err != nil {
		log.Fatalln("ListenAndServe: ", err)
	}
}
func Dial(network, address string) (net.Conn, error) {
	return conn, nil
}
func main() {
	startServer()
}

具体框架就是在这样,语法不一定对。

客户端代码(大概):

func proxy(local, remote string) {
	conf := &tls.Config{
		InsecureSkipVerify: true,
	}
	rp, err := tls.Dial("tcp", remote, conf)
	if err != nil {
		beego.Error("Can't' connect:", remote, " err:", err)
		return
	}
	defer util.CloseConn(rp)

	
	config := &tls.Config{InsecureSkipVerify: true} //不做证书校验

	lp, err := tls.Dial("tcp", local, config)
	if err != nil {
		beego.Error("Can't' connect:", other, " err:", err)
		rp.Close()
		return
	}
	defer util.CloseConn(lp)
	//buf = make([]byte, 1024*1024)

	rp.SetReadDeadline(time.Time{})
	lp.SetReadDeadline(time.Time{})
	flag := make(chan error)
	go Transfer(rp, lp, flag)
	

}

func Transfer(a, b net.Conn, flag chan error) {

	cp := func(r, w net.Conn) {
		n, err := io.Copy(r, w)
		r.Close()
		w.Close()
		beego.Debug("Transfer", n, " bytes between ", a.RemoteAddr(), " and ", b.RemoteAddr())
		flag <- err
	}
	go cp(a, b)
	go cp(b, a)

}

main(){
//本地服务地址和代理服务器接受内网服务器连接的地址
 proxy("127.0.0.1:443","192.168.16.110:8088")
}

以上仅是大概框架,以供参考


有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:idwtwt

查看原文:go库中自带的反向代理功能和内网代理

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

5804 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传