Surf is a powerful, feature-rich HTTP client library for Go that makes working with HTTP requests intuitive and enjoyable. With advanced features like browser impersonation, JA3/JA4 fingerprinting, and comprehensive middleware support, Surf provides everything you need for modern web interactions.
Error Handling: Result type pattern for better error management
Context Support: Full context.Context integration for cancellation and timeouts
go get -u github.com/enetx/surf
Required Go version: 1.24+
🔄 Standard Library Compatibility
Surf provides seamless integration with Go's standard net/http package, allowing you to use Surf's advanced features with any library that expects a standard *http.Client.
// Create a Surf client with advanced featuressurfClient:=surf.NewClient().
Builder().
Impersonate().Chrome().
Session().
Build()
// Convert to standard net/http.ClientstdClient:=surfClient.Std()
// Use with any third-party library// Example: AWS SDK, Google APIs, OpenAI client, etc.resp, err:=stdClient.Get("https://api.example.com")
// With HTTP proxy - automatically falls back to HTTP/2client:=surf.NewClient().
Builder().
Proxy("http://proxy:8080"). // HTTP proxies incompatible with HTTP/3HTTP3Settings().Chrome().Set(). // Will use HTTP/2 insteadBuild()
// With SOCKS5 proxy - HTTP/3 works over UDPclient:=surf.NewClient().
Builder().
Proxy("socks5://127.0.0.1:1080"). // SOCKS5 UDP proxy supports HTTP/3HTTP3Settings().Chrome().Set(). // Will use HTTP/3 over SOCKS5Build()
// With DNS settings - works seamlesslyclient:=surf.NewClient().
Builder().
DNS("8.8.8.8:53"). // Custom DNS works with HTTP/3HTTP3Settings().Chrome().Set().
Build()
// With DNS-over-TLS - works seamlesslyclient:=surf.NewClient().
Builder().
DNSOverTLS().Google(). // DoT works with HTTP/3HTTP3Settings().Chrome().Set().
Build()
Key HTTP/3 Features:
✅ Complete QUIC Fingerprinting: Full Chrome and Firefox QUIC transport parameter matching
// Standard form data (field order not guaranteed)formData:=map[string]string{
"username": "john",
"password": "secret",
}
resp:=surf.NewClient().
Post("https://example.com/login", formData).
Do()
// Ordered form data (preserves field insertion order)orderedForm:=g.NewMapOrd[string, string]()
orderedForm.Set("username", "john")
orderedForm.Set("password", "secret")
orderedForm.Set("remember_me", "true")
resp:=surf.NewClient().
Post("https://example.com/login", orderedForm).
Do()
// Single file uploadresp:=surf.NewClient().
FileUpload(
"https://api.example.com/upload",
"file", // field name"/path/to/file.pdf", // file path
).Do()
// With additional form fieldsextraData:= g.MapOrd[string, string]{
"description": "Important document",
"category": "reports",
}
resp:=surf.NewClient().
FileUpload(
"https://api.example.com/upload",
"file",
"/path/to/file.pdf",
extraData,
).Do()
// Create a reusable clientclient:=surf.NewClient().
Builder().
Singleton(). // Enable connection poolingImpersonate().
Chrome().
Build()
// Reuse for multiple requestsfori:=0; i<100; i++ {
resp:=client.Get("https://api.example.com/data").Do()
// Process response
}
// Clean up when donedeferclient.CloseIdleConnections()
client:=surf.NewClient().
Builder().
CacheBody(). // Enable body cachingBuild()
resp:=client.Get("https://api.example.com/data").Do()
ifresp.IsOk() {
// First access reads from networkdata1:=resp.Ok().Body.Bytes()
// Subsequent accesses use cachedata2:=resp.Ok().Body.Bytes() // No network I/O
}
client:=surf.NewClient().
Builder().
Retry(3, 2*time.Second). // Max 3 retries, 2 second waitRetryCodes(http.StatusTooManyRequests, http.StatusServiceUnavailable).
Build()
// Enable HTTP/2 without TLSclient:=surf.NewClient().
Builder().
H2C().
Build()
resp:=client.Get("http://localhost:8080/h2c-endpoint").Do()
// Control exact header order for fingerprinting evasionheaders:=g.NewMapOrd[g.String, g.String]()
headers.Set("User-Agent", "Custom/1.0")
headers.Set("Accept", "*/*")
headers.Set("Accept-Language", "en-US")
headers.Set("Accept-Encoding", "gzip, deflate")
client:=surf.NewClient().
Builder().
SetHeaders(headers). // Headers will be sent in this exact orderBuild()
client:=surf.NewClient().
Builder().
Resolver("8.8.8.8:53"). // Use Google DNSBuild()
Set proxy configuration (string, []string for rotation)
DNS(dns)
Set custom DNS resolver
DNSOverTLS()
Configure DNS-over-TLS
Session()
Enable cookie jar for sessions
Singleton()
Enable connection pooling (reuse client)
Timeout(duration)
Set request timeout
MaxRedirects(n)
Set maximum redirects
NotFollowRedirects()
Disable redirect following
FollowOnlyHostRedirects()
Only follow same-host redirects
ForwardHeadersOnRedirect()
Forward headers on redirects
RedirectPolicy(fn)
Custom redirect policy function
Retry(max, wait, codes...)
Configure retry logic
CacheBody()
Enable response body caching
With(middleware, priority...)
Add middleware
BasicAuth(auth)
Set basic authentication
BearerAuth(token)
Set bearer token authentication
UserAgent(ua)
Set custom user agent
SetHeaders(headers...)
Set request headers
AddHeaders(headers...)
Add request headers
AddCookies(cookies...)
Add cookies
WithContext(ctx)
Add context
ContentType(type)
Set content type
GetRemoteAddress()
Track remote address
DisableKeepAlive()
Disable keep-alive
DisableCompression()
Disable compression
ForceHTTP1()
Force HTTP/1.1
UnixDomainSocket(path)
Use Unix socket
InterfaceAddr(addr)
Bind to network interface
Boundary(fn)
Custom multipart boundary generator
Std()
Convert to standard net/http.Client
Method
Description
Do()
Execute the request
WithContext(ctx)
Add context to request
SetHeaders(headers...)
Set request headers
AddHeaders(headers...)
Add request headers
AddCookies(cookies...)
Add cookies to request
Property
Type
Description
StatusCode
StatusCode
HTTP status code
Headers
Headers
Response headers
Cookies
Cookies
Response cookies
Body
*Body
Response body
URL
*url.URL
Final URL after redirects
Time
time.Duration
Request duration
ContentLength
int64
Content length
Proto
string
HTTP protocol version
Attempts
int
Number of retry attempts
Method
Description
String()
Get body as string
Bytes()
Get body as bytes
JSON(v)
Decode JSON into struct
XML(v)
Decode XML into struct
MD5()
Calculate MD5 hash
UTF8()
Convert to UTF-8
Stream()
Get buffered reader
SSE(fn)
Process Server-Sent Events
Dump(file)
Save to file
Contains(pattern)
Check if contains pattern
Limit(n)
Limit body size
Close()
Close body reader
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
Fork the repository
Create your feature branch (git checkout -b feature/AmazingFeature)
Commit your changes (git commit -m 'Add some AmazingFeature')
Push to the branch (git push origin feature/AmazingFeature)
Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
Built with enetx/http for enhanced HTTP functionality
HTTP/3 support and complete QUIC fingerprinting powered by uQUIC