Need help with goproxy?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

ouqiang
194 Stars 59 Forks Apache License 2.0 18 Commits 11 Opened issues

Description

Go HTTP(S)代理库, 支持中间人代理解密HTTPS

Services available

!
?

Need anything else?

Contributors list

# 7,938
Google
Go
Redis
golang
9 commits

goproxy

Go HTTP(S)代理库, 支持中间人代理解密HTTPS

安装

go get github.com/ouqiang/goproxy

使用

package main

import ( "net/http" "time"

"github.com/ouqiang/goproxy"

)

func main() { proxy := goproxy.New() server := &http.Server{ Addr: ":8080", Handler: proxy, ReadTimeout: 1 * time.Minute, WriteTimeout: 1 * time.Minute, } err := server.ListenAndServe() if err != nil { panic(err) } }

代理测试

curl -x localhost:8080 https://www.baidu.com

中间人代理, 解密HTTPS

系统需导入根证书 mitm-proxy.crt ```go package main

import ( "crypto/tls" "net/http" "sync" "time"

"github.com/ouqiang/goproxy"

) // 实现证书缓存接口 type Cache struct { m sync.Map }

func (c *Cache) Set(host string, cert *tls.Certificate) { c.m.Store(host, cert) } func (c *Cache) Get(host string) *tls.Certificate { v, ok := c.m.Load(host) if !ok { return nil }

return v.(*tls.Certificate)

}

func main() { proxy := goproxy.New(goproxy.WithDecryptHTTPS(&Cache{})) server := &http.Server{ Addr: ":8080", Handler: proxy, ReadTimeout: 1 * time.Minute, WriteTimeout: 1 * time.Minute, } err := server.ListenAndServe() if err != nil { panic(err) } } ```

事件处理

实现Delegate接口

go
type Delegate interface {
    // Connect 收到客户端连接
    Connect(ctx *Context, rw http.ResponseWriter)
    // Auth 代理身份认证
    Auth(ctx *Context, rw http.ResponseWriter)
    // BeforeRequest HTTP请求前 设置X-Forwarded-For, 修改Header、Body
    BeforeRequest(ctx *Context)
    // BeforeResponse 响应发送到客户端前, 修改Header、Body、Status Code
    BeforeResponse(ctx *Context, resp *http.Response, err error)
    // ParentProxy 上级代理
    ParentProxy(*http.Request) (*url.URL, error)
    // Finish 本次请求结束
    Finish(ctx *Context)
    // 记录错误信息
    ErrorLog(err error)
}
```go type EventHandler struct{}

func (e *EventHandler) Connect(ctx *goproxy.Context, rw http.ResponseWriter) { // 保存的数据可以在后面的回调方法中获取 ctx.Data["req_id"] = "uuid"

// 禁止访问某个域名
if strings.Contains(ctx.Req.URL.Host, "example.com") {
    rw.WriteHeader(http.StatusForbidden)
    ctx.Abort()
    return
}

}

func (e *EventHandler) Auth(ctx *goproxy.Context, rw http.ResponseWriter) { // 身份验证 }

func (e *EventHandler) BeforeRequest(ctx *goproxy.Context) { // 修改header ctx.Req.Header.Add("X-Request-Id", ctx.Data["req_id"].(string)) // 设置X-Forwarded-For if clientIP, _, err := net.SplitHostPort(ctx.Req.RemoteAddr); err == nil { if prior, ok := ctx.Req.Header["X-Forwarded-For"]; ok { clientIP = strings.Join(prior, ", ") + ", " + clientIP } ctx.Req.Header.Set("X-Forwarded-For", clientIP) } // 读取Body body, err := ioutil.ReadAll(ctx.Req.Body) if err != nil { // 错误处理 return } // Request.Body只能读取一次, 读取后必须再放回去 // Response.Body同理 ctx.Req.Body = ioutil.NopCloser(bytes.NewReader(body))

}

func (e *EventHandler) BeforeResponse(ctx *goproxy.Context, resp *http.Response, err error) { if err != nil { return } // 修改response }

// 设置上级代理 func (e EventHandler) ParentProxy(req *http.Request) (url.URL, error) { return url.Parse("http://localhost:1087") }

func (e *EventHandler) Finish(ctx *goproxy.Context) { fmt.Printf("请求结束 URL:%s\n", ctx.Req.URL) }

// 记录错误日志 func (e *EventHandler) ErrorLog(err error) { log.Println(err) }

func main() { proxy := goproxy.New(goproxy.WithDelegate(&EventHandler{})) server := &http.Server{ Addr: ":8080", Handler: proxy, ReadTimeout: 1 * time.Minute, WriteTimeout: 1 * time.Minute, } err := server.ListenAndServe() if err != nil { panic(err) } }

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.