v1.10.82-f67ee7d
Skip to main content
← Back to Code Snippets

Go net/http Proxy

Complete net/http proxy integration example for Go with Hex Proxies. Includes authentication, timeouts, and error handling.

Gonet/http
Install:go mod init myproject
Go / net/http
package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"time"
)

func main() {
	proxyURL, err := url.Parse("http://user:pass@gate.hexproxies.com:8080")
	if err != nil {
		log.Fatal("Invalid proxy URL:", err)
	}

	client := &http.Client{
		Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL)},
		Timeout:   30 * time.Second,
	}

	resp, err := client.Get("https://httpbin.org/ip")
	if err != nil {
		log.Fatal("Request failed:", err)
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Println("Response:", string(body))
}

Why Go for Proxy Work

Go has emerged as the language of choice for building proxy infrastructure itself, and for good reason: its compiled binaries start instantly, its goroutine model handles massive concurrency with minimal memory overhead, and its standard library includes production-grade HTTP client and server implementations. When you use Go for proxy-driven applications, you benefit from the same performance characteristics that power proxy servers, load balancers, and CDN edge nodes built in Go at companies like Cloudflare, Fastly, and Docker.

Go's goroutine model is fundamentally different from threading in other languages. Launching 10,000 goroutines to make concurrent proxied requests through gate.hexproxies.com:8080 costs roughly 20MB of memory, compared to gigabytes for equivalent thread-based concurrency in Java or Python. Each goroutine is multiplexed onto a small number of OS threads by the Go scheduler, eliminating context-switching overhead. This means a modest Go program can saturate a proxy gateway's throughput capacity from a single machine, making Go ideal for high-volume data collection, availability monitoring, and price intelligence systems.

Configuration Patterns

Go's `net/http` package provides proxy support through the `Transport.Proxy` field, which accepts a function that returns a proxy URL for each request. The simplest approach uses `http.ProxyURL()` for a static proxy, but for rotation you can supply a custom function that selects proxies based on the target URL, request count, or geographic requirements. The `Transport` struct also controls connection pooling, TLS configuration, and dial timeouts, giving you low-level control over the proxy connection lifecycle.

For proxy authentication, embed credentials in the URL passed to `url.Parse()`. Go's HTTP transport automatically extracts the userinfo from the proxy URL and adds the `Proxy-Authorization` header to CONNECT requests. If you need to customize authentication (for example, adding session identifiers to the username), construct the URL programmatically using the `url.URL` struct with its `User` field set via `url.UserPassword()`.

Common Pitfalls

The most dangerous mistake in Go proxy code is neglecting to close response bodies. Every `http.Client.Do()` or `client.Get()` call returns a response whose body must be fully read and closed, even if you do not need the content. Failing to close response bodies leaks TCP connections in the transport's pool, eventually exhausting the proxy connection limit and causing all subsequent requests to block. Always use `defer resp.Body.Close()` immediately after checking the error from the HTTP call.

Another Go-specific pitfall is using the `http.DefaultClient` for proxy work. The default client has no timeout, which means a stalled proxy connection will block the goroutine forever. It also uses `http.DefaultTransport`, which reads the `HTTP_PROXY` environment variable, potentially routing requests through an unintended proxy. Always create an explicit `http.Client` with a configured `Transport` and `Timeout` to maintain full control over proxy routing and failure behavior.

Performance Optimization

Tune the `Transport` connection pool settings for your proxy workload. Set `MaxIdleConns` to the total number of connections you want pooled across all hosts, `MaxIdleConnsPerHost` to the number of idle connections to keep open to the proxy gateway, and `IdleConnTimeout` to close idle connections after a specified duration. For a workload sending all traffic through a single proxy gateway, set `MaxIdleConnsPerHost` equal to your target concurrency to prevent the transport from closing and reopening connections.

Use Go's `context` package for request-level timeout and cancellation control. Create a context with `context.WithTimeout()` and attach it to requests via `http.NewRequestWithContext()`. This gives you per-request timeout control that is independent of the client-level timeout, and it integrates with Go's cancellation propagation so that upstream callers can cancel in-flight proxy requests cleanly. Monitor goroutine counts with `runtime.NumGoroutine()` to detect goroutine leaks from unresolved proxy connections.

Tips

  • 1
    Use http.ProxyURL for static proxy config or http.ProxyFromEnvironment for env-based setup.
  • 2
    Set Transport.MaxIdleConnsPerHost to control connection pooling to the proxy.
  • 3
    Always defer resp.Body.Close() to prevent resource leaks.

Ready to Integrate?

Get proxy credentials and start coding in minutes.