求助:基于现有net.Conn的Go代理服务器实现及HTTP请求方案
基于Snowflake net.Conn的Go代理实现与直接HTTP请求方案
一、用现有net.Conn实现HTTP代理转发
你可以实现一个简单的HTTP代理服务器,将本地客户端的HTTP请求通过Snowflake建立的net.Conn转发出去,再把远端响应回传给本地客户端。核心逻辑是双向数据拷贝:将客户端连接的数据拷贝到Snowflake conn,同时将Snowflake conn的数据拷贝回客户端连接。
以下是结合你的Snowflake代码的完整实现:
package main import ( "io" "log" "net" "net/http" sf "git.torproject.org/pluggable-transports/snowflake.git/v2/client/lib" ) // 代理处理器:将HTTP请求转发到Snowflake连接 func proxyHandler(snowflakeConn net.Conn) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // 修改请求目标:代理场景下需将请求URL设为完整地址 r.RequestURI = "" r.URL.Scheme = "http" // 若需HTTPS,需在Snowflake conn之上建立TLS连接 r.URL.Host = "目标服务器地址:端口" // 替换为实际要访问的服务地址 // 将HTTP请求写入Snowflake连接 if err := r.Write(snowflakeConn); err != nil { log.Printf("写入Snowflake连接失败: %v", err) w.WriteHeader(http.StatusServiceUnavailable) return } // 读取Snowflake连接返回的响应,回传给客户端 _, err := io.Copy(w, snowflakeConn) if err != nil { log.Printf("响应回传客户端失败: %v", err) } } } func main() { // 初始化Snowflake客户端(原有代码) config := sf.ClientConfig{ BrokerURL: "https://snowflake-broker.torproject.net.global.prod.fastly.net/", FrontDomain: "cdn.sstatic.net", ICEAddresses: []string{ "stun:stun.voip.blackberry.com:3478", "stun:stun.stunprotocol.org:3478", "stun:stun.altar.com.pl:3478", "stun:stun.antisip.com:3478", "stun:stun.bluesip.net:3478", "stun:stun.dus.net:3478", "stun:stun.epygi.com:3478", "stun:stun.sonetel.com:3478", "stun:stun.sonetel.net:3478", "stun:stun.uls.co.za:3478", "stun:stun.voipgate.com:3478", "stun:stun.voys.nl:3478"}, Max: 1, } transport, err := sf.NewSnowflakeClient(config) if err != nil { log.Fatal("启动Snowflake传输失败: ", err) } // 建立Snowflake连接 conn, err := transport.Dial() if err != nil { log.Printf("连接失败: %s", err) return } defer conn.Close() // 启动本地HTTP代理,监听8080端口 log.Println("HTTP代理已启动,监听端口:8080") http.HandleFunc("/", proxyHandler(conn)) if err := http.ListenAndServe(":8080", nil); err != nil { log.Fatal("代理服务器启动失败: ", err) } }
注意事项
- 若需支持HTTPS代理,需在Snowflake conn之上包装TLS客户端:
tlsClient := tls.Client(conn, &tls.Config{ServerName: "目标域名"}),之后使用tlsClient进行读写。 - 若要实现SOCKS5代理,逻辑类似,只需替换协议解析部分,核心仍是双向数据拷贝。
二、直接通过net.Conn发送HTTP请求(不使用http.Client)
如果不需要代理服务器,仅需直接通过Snowflake连接发送HTTP请求,可以手动构造符合HTTP协议格式的报文,写入net.Conn后读取响应。
示例代码如下:
package main import ( "bufio" "log" "net" "strings" sf "git.torproject.org/pluggable-transports/snowflake.git/v2/client/lib" ) func main() { // 初始化Snowflake客户端(原有代码) config := sf.ClientConfig{ BrokerURL: "https://snowflake-broker.torproject.net.global.prod.fastly.net/", FrontDomain: "cdn.sstatic.net", ICEAddresses: []string{ "stun:stun.voip.blackberry.com:3478", "stun:stun.stunprotocol.org:3478", "stun:stun.altar.com.pl:3478", "stun:stun.antisip.com:3478", "stun:stun.bluesip.net:3478", "stun:stun.dus.net:3478", "stun:stun.epygi.com:3478", "stun:stun.sonetel.com:3478", "stun:stun.sonetel.net:3478", "stun:stun.uls.co.za:3478", "stun:stun.voipgate.com:3478", "stun:stun.voys.nl:3478"}, Max: 1, } transport, err := sf.NewSnowflakeClient(config) if err != nil { log.Fatal("启动Snowflake传输失败: ", err) } // 建立Snowflake连接 conn, err := transport.Dial() if err != nil { log.Printf("连接失败: %s", err) return } defer conn.Close() // 手动构造HTTP GET请求报文(严格遵循HTTP协议格式) request := "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n" // 写入Snowflake连接 _, err = conn.Write([]byte(request)) if err != nil { log.Fatal("写入请求失败: ", err) } // 读取并打印响应 scanner := bufio.NewScanner(conn) for scanner.Scan() { log.Println(scanner.Text()) } if err := scanner.Err(); err != nil { log.Fatal("读取响应失败: ", err) } }
说明
- 手动构造HTTP请求时,必须严格遵守协议规范:行尾使用
\r\n,请求头结束后需添加空行(\r\n\r\n)。 - 发送POST请求时,需额外添加
Content-Length头,并在空行后写入请求体内容。
内容的提问来源于stack exchange,提问作者daniel atlass
相关产品推荐
相关产品推荐

