下面的代码是保存为socks2http.go , 执行如下代码

go mod init example.com/m
go mod tidy
GOOS=linux  GOARCH=amd64 go build  socks2http.go

# 可以通过 go tool dist list 获取
PLATFORMS=(
  "linux/amd64"
  "linux/arm64"
  "darwin/amd64"
  "darwin/arm64"
  "windows/amd64"
)
# 运行
socks2http -http=:8181 -socks=127.0.0.1:41080

源码如下:

package main

import (
    "context"
    "flag"
    "fmt"
    "io"
    "log"
    "net"
    "net/http"
    "os"
    "time"

    "golang.org/x/net/proxy"
)

var (
    httpAddr  = flag.String("http", ":8080", "HTTP proxy listen address")
    socksAddr = flag.String("socks", "127.0.0.1:1080", "SOCKS5 proxy address")
    help      = flag.Bool("help", false, "Show this help message")
)

func printUsage() {
    fmt.Fprintf(os.Stderr, "Usage: %s [options]\n", os.Args[0])
    fmt.Fprintln(os.Stderr, "Convert a SOCKS5 proxy to an HTTP proxy.")
    fmt.Fprintln(os.Stderr, "")
    fmt.Fprintln(os.Stderr, "Options:")
    flag.PrintDefaults()
    fmt.Fprintln(os.Stderr, "")
    fmt.Fprintln(os.Stderr, "Example:")
    fmt.Fprintln(os.Stderr, "  ./socks2http -http=:8118 -socks=127.0.0.1:1080")
}
func main() {
    // 解析命令行参数
    flag.Parse()

    // 如果用户请求 help,或没有提供任何非-flag 参数(且未设置有效选项)
    // 注意:flag.NArg() == 0 表示没有额外 positional arguments
    if *help || (len(os.Args) == 1) {
        printUsage()
        os.Exit(0)
    }

    // 创建 SOCKS5 拨号器
    socksDialer, err := proxy.SOCKS5("tcp", *socksAddr, nil, &net.Dialer{
        Timeout:   30 * time.Second,
        KeepAlive: 30 * time.Second,
    })
    if err != nil {
        log.Fatalf("Failed to create SOCKS5 dialer: %v", err)
    }

    // 自定义 DialContext 使用 SOCKS5
    transport := &http.Transport{
        DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
            return socksDialer.Dial(network, addr)
        },
        // 禁用 HTTP/2 避免某些兼容性问题(可选)
        ForceAttemptHTTP2:     false,
        MaxIdleConns:          100,
        IdleConnTimeout:       90 * time.Second,
        TLSHandshakeTimeout:   10 * time.Second,
        ExpectContinueTimeout: 1 * time.Second,
    }

    // 创建 HTTP 代理处理器
    proxyHandler := &httpProxyHandler{
        transport: transport,
        socksAddr: *socksAddr,
    }

    server := &http.Server{
        Addr:    *httpAddr,
        Handler: proxyHandler,
    }

    fmt.Printf("HTTP proxy listening on %s, forwarding to SOCKS5 %s\n", *httpAddr, *socksAddr)
    log.Fatal(server.ListenAndServe())
}

// httpProxyHandler 实现 HTTP 代理逻辑
type httpProxyHandler struct {
    transport *http.Transport
    socksAddr string
}

func (h *httpProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // 处理 CONNECT 请求(用于 HTTPS)
    if r.Method == http.MethodConnect {
        h.handleConnect(w, r)
        return
    }

    // 处理普通 HTTP 请求(GET/POST 等)
    h.handleHTTP(w, r)
}

func (h *httpProxyHandler) handleConnect(w http.ResponseWriter, r *http.Request) {
    // 建立到目标服务器的连接(通过 SOCKS5)
    targetConn, err := h.transport.DialContext(context.Background(), "tcp", r.Host)
    if err != nil {
        http.Error(w, fmt.Sprintf("Failed to connect to %s: %v", r.Host, err), http.StatusServiceUnavailable)
        return
    }
    clientIP, _, _ := net.SplitHostPort(r.RemoteAddr)
    log.Printf("[HTTPS] Client %s -> Target %s %s %s", clientIP, r.URL.Host, r.Method, r.URL.Path)
    defer targetConn.Close()

    // 通知客户端连接已建立
    w.WriteHeader(http.StatusOK)

    // Hijack HTTP 连接,进行双向数据转发
    hijacker, ok := w.(http.Hijacker)
    if !ok {
        http.Error(w, "Hijacking not supported", http.StatusInternalServerError)
        return
    }

    clientConn, _, err := hijacker.Hijack()
    if err != nil {
        log.Printf("Hijack failed: %v", err)
        return
    }
    defer clientConn.Close()

    // 双向复制数据
    go io.Copy(targetConn, clientConn)
    io.Copy(clientConn, targetConn)
}

func (h *httpProxyHandler) handleHTTP(w http.ResponseWriter, r *http.Request) {
    clientIP, _, _ := net.SplitHostPort(r.RemoteAddr)
    log.Printf("[HTTP] Client %s -> Target %s %s %s", clientIP, r.URL.Host, r.Method, r.URL.Path)
    // 修改请求 URL 为绝对路径(代理要求)
    if r.URL.Scheme == "" {
        r.URL.Scheme = "http"
    }
    if r.URL.Host == "" {
        r.URL.Host = r.Host
    }

    // 使用自定义 transport 发送请求(走 SOCKS5)
    resp, err := h.transport.RoundTrip(r)
    if err != nil {
        http.Error(w, fmt.Sprintf("Request failed: %v", err), http.StatusServiceUnavailable)
        return
    }
    defer resp.Body.Close()

    // 复制响应头
    for key, values := range resp.Header {
        for _, value := range values {
            w.Header().Add(key, value)
        }
    }
    w.WriteHeader(resp.StatusCode)

    // 复制响应体
    io.Copy(w, resp.Body)
}