go 实现 端口代理
时间:2022-6-1 10:33
热度:1864°
评论:0 条

package main
import (
"bytes"
"compress/gzip"
"flag"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"os/exec"
"runtime"
)
/**
启动
-port=8080 -target=http://127.0.0.1:9411
*/
var (
targetURL *url.URL
targetAddr *string //要代理的服务的http地址
)
/*
编译跨平台的只需要修改GOOS、GOARCH、CGO_ENABLED三个环境变量即可
GOOS:目标平台的操作系统(darwin、freebsd、linux、windows)
GOARCH:目标平台的体系架构32位还是64位(386、amd64、arm)
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
go build
*/
//参数识别
func Daemonize(args ...string) {
sysType := runtime.GOOS
if sysType == "linux" {
var arg []string
if len(args) > 1 {
arg = args[1:]
}
fmt.Println("run in backMode")
cmd := exec.Command(args[0], arg...)
cmd.Env = os.Environ()
cmd.Start()
} else if sysType == "windows" {
}
}
func printMsg(r *http.Request) error {
//gzip压缩格式
if r.Header.Get("Content-Encoding") == "gzip" {
fmt.Println("Content-Encoding: " + r.Header.Get("Content-Encoding"))
reader, e := gzip.NewReader(r.Body)
if e != nil {
fmt.Printf("create gzip reader err: %s \n", e.Error())
return e
} else {
//ioutil.ReadAll() 读取之后会关闭流
//这里读出之后再新建一个流然后重新赋值
bodyBytes, e := ioutil.ReadAll(reader)
if e != nil {
fmt.Printf("read request body err: %s \n", e.Error())
return e
} else {
if len(bodyBytes) > 0 {
fmt.Println(string(bodyBytes))
}
}
//需要将数据再以gzip格式压缩,否则和header中的content-length对不上
var zBuf bytes.Buffer
zw := gzip.NewWriter(&zBuf)
if _, err := zw.Write(bodyBytes); err != nil {
return err
}
zw.Close()
r.Body = ioutil.NopCloser(&zBuf)
}
} else {
//其它压缩格式
bodyBytes, e := ioutil.ReadAll(r.Body)
r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
if e != nil {
fmt.Printf("read request body err: %s \n", e.Error())
return e
} else {
if len(bodyBytes) > 0 {
fmt.Println(string(bodyBytes))
}
}
}
return nil
}
func proxy(w http.ResponseWriter, r *http.Request) {
if e := printMsg(r); e != nil {
_, _ = fmt.Fprint(w, e.Error())
return
}
o := new(http.Request)
*o = *r
o.Host = targetURL.Host
o.URL.Scheme = targetURL.Scheme
o.URL.Host = targetURL.Host
o.URL.Path = r.URL.Path
o.URL.RawQuery = r.URL.RawQuery
o.Proto = r.Proto
o.ProtoMajor = 1
o.ProtoMinor = 1
o.Close = false
res, err := http.DefaultTransport.RoundTrip(o)
if err != nil {
fmt.Printf("http: proxy error: %v\n", err)
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
return
}
hdr := w.Header()
for k, vv := range res.Header {
for _, v := range vv {
hdr.Add(k, v)
}
}
for _, c := range res.Cookies() {
w.Header().Add("Set-Cookie", c.Raw)
}
w.WriteHeader(res.StatusCode)
if res.Body != nil {
_, _ = io.Copy(w, res.Body)
}
}
func main() {
args := os.Args
daemon := false
for k, v := range args {
if v == "-d" {
daemon = true
args[k] = ""
} else if v == "restart" {
daemon = true
args[k] = ""
}
}
if daemon {
Daemonize(args...)
return
}
//代理自身的端口号
port := flag.Int("port", 8098, "Http proxy liston port")
//后端服务的地址
targetAddr = flag.String("target", "https://api-testing.phonepe.com", "The server address. Format: http://ip:port")
flag.Parse()
addr := fmt.Sprintf(":%d", *port)
fmt.Println("proxy addr: " + addr)
fmt.Println("target addr: " + *targetAddr)
if *port <= 0 {
panic("proxy port is invalid!")
}
if len(*targetAddr) == 0 {
panic("target addr is empty! Format: http://ip:port")
}
var e error
targetURL, e = url.Parse(*targetAddr)
if e != nil {
panic(e.Error())
}
http.HandleFunc("/", proxy)
err := http.ListenAndServe(addr, nil)
if err != nil {
panic(err.Error())
}
}


捐赠支持:如果觉得这篇文章对您有帮助,请“扫一扫”鼓励作者!







发表吐槽
你肿么看?
既然没有吐槽,那就赶紧抢沙发吧!