HTTP Client
The HTTPClient
provides a comprehensive HTTP client with built-in rate limiting, automatic retry logic, and thread-safe operation. It's designed for reliable API communication with proper error handling and resource management.
HTTPClient
type HTTPClient struct {
client *http.Client // Underlying HTTP client
rateLimiter *HTTPRateLimiter // Rate limiting controller
maxRetries int // Maximum retry attempts
retryDelay time.Duration // Delay between retries
}
The HTTPClient is thread-safe and can be used concurrently across multiple goroutines.
Configuration Options
ClientOption
type ClientOption func(*HTTPClient)
Function type for configuring HTTPClient instances.
WithMaxRetries
func WithMaxRetries(maxRetries int) ClientOption
Sets the maximum number of retry attempts.
Parameters:
maxRetries
- Number of retries (must be > 0)
WithRetryInterval
func WithRetryInterval(interval time.Duration) ClientOption
Sets the delay between retry attempts.
Parameters:
interval
- Retry delay duration (must be > 0)
WithRateLimit
func WithRateLimit(requestsPerSecond float64) ClientOption
Sets the rate limit in requests per second.
Parameters:
requestsPerSecond
- Requests per second (must be > 0)
Constructors
NewHttpClient
func NewHttpClient(options ...ClientOption) *HTTPClient
Creates a new HTTP client with optional configuration.
Default Configuration:
- Timeout: 30 seconds
- Rate limit: 1 request per 10 seconds
- Max retries: 3
- Retry delay: 1 second
Parameters:
options
- Variable number of configuration options
Example:
// Default client
client := cwe.NewHttpClient()
// Custom configuration
client := cwe.NewHttpClient(
cwe.WithMaxRetries(5),
cwe.WithRetryInterval(2 * time.Second),
cwe.WithRateLimit(0.5), // 1 request per 2 seconds
)
NewHTTPClient
func NewHTTPClient(httpClient *http.Client, rateLimiter *HTTPRateLimiter, maxRetries int, retryDelay time.Duration) *HTTPClient
Creates a new HTTP client with explicit parameters.
Parameters:
httpClient
- Underlying HTTP clientrateLimiter
- Rate limiter instancemaxRetries
- Maximum retry attemptsretryDelay
- Delay between retries
Example:
httpClient := &http.Client{Timeout: 60 * time.Second}
rateLimiter := cwe.NewHTTPRateLimiter(5 * time.Second)
client := cwe.NewHTTPClient(httpClient, rateLimiter, 3, time.Second)
HTTP Methods
Get
func (c *HTTPClient) Get(ctx context.Context, url string) (*http.Response, error)
Sends an HTTP GET request with context support.
Parameters:
ctx
- Request context for cancellation/timeouturl
- Target URL
Returns:
*http.Response
- HTTP responseerror
- Request error
Example:
ctx := context.Background()
resp, err := client.Get(ctx, "https://api.example.com/data")
if err != nil {
log.Fatalf("GET request failed: %v", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatalf("Failed to read response: %v", err)
}
Post
func (c *HTTPClient) Post(ctx context.Context, url string, data []byte) (*http.Response, error)
Sends an HTTP POST request with JSON data.
Parameters:
ctx
- Request contexturl
- Target URLdata
- Request body data
Returns:
*http.Response
- HTTP responseerror
- Request error
Example:
data := []byte(`{"key": "value"}`)
resp, err := client.Post(ctx, "https://api.example.com/data", data)
if err != nil {
log.Fatalf("POST request failed: %v", err)
}
defer resp.Body.Close()
PostForm
func (c *HTTPClient) PostForm(ctx context.Context, url string, data url.Values) (*http.Response, error)
Sends an HTTP POST request with form data.
Parameters:
ctx
- Request contexturl
- Target URLdata
- Form values
Returns:
*http.Response
- HTTP responseerror
- Request error
Example:
formData := url.Values{
"username": []string{"user123"},
"password": []string{"secret"},
}
resp, err := client.PostForm(ctx, "https://api.example.com/login", formData)
if err != nil {
log.Fatalf("Form POST failed: %v", err)
}
defer resp.Body.Close()
Do
func (c *HTTPClient) Do(req *http.Request) (*http.Response, error)
Executes an HTTP request with rate limiting and retry logic.
Parameters:
req
- HTTP request to execute
Returns:
*http.Response
- HTTP responseerror
- Request error
Example:
req, err := http.NewRequest("PUT", "https://api.example.com/data", strings.NewReader("data"))
if err != nil {
log.Fatalf("Failed to create request: %v", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer token123")
resp, err := client.Do(req)
if err != nil {
log.Fatalf("Request failed: %v", err)
}
defer resp.Body.Close()
Configuration Methods
SetClient
func (c *HTTPClient) SetClient(client *http.Client)
Sets the underlying HTTP client.
Parameters:
client
- New HTTP client (nil values are ignored)
GetClient
func (c *HTTPClient) GetClient() *http.Client
Returns the underlying HTTP client.
SetRateLimiter
func (c *HTTPClient) SetRateLimiter(limiter *HTTPRateLimiter)
Sets a new rate limiter.
Parameters:
limiter
- New rate limiter (nil values are ignored)
GetRateLimiter
func (c *HTTPClient) GetRateLimiter() *HTTPRateLimiter
Returns the current rate limiter.
SetMaxRetries
func (c *HTTPClient) SetMaxRetries(maxRetries int)
Sets the maximum number of retry attempts.
SetRetryDelay
func (c *HTTPClient) SetRetryDelay(delay time.Duration)
Sets the delay between retry attempts.
Close
func (c *HTTPClient) Close()
Closes the HTTP client and cleans up resources.
Global Instances
DefaultHTTPClient
var DefaultHTTPClient = NewHttpClient()
Default HTTP client instance with standard configuration.
Usage Examples
Basic Usage
// Create client with default settings
client := cwe.NewHttpClient()
defer client.Close()
// Simple GET request
ctx := context.Background()
resp, err := client.Get(ctx, "https://api.example.com/data")
if err != nil {
log.Fatalf("Request failed: %v", err)
}
defer resp.Body.Close()
fmt.Printf("Status: %d\n", resp.StatusCode)
Custom Configuration
// Create client with custom settings
client := cwe.NewHttpClient(
cwe.WithMaxRetries(5), // Retry up to 5 times
cwe.WithRetryInterval(2 * time.Second), // Wait 2 seconds between retries
cwe.WithRateLimit(0.2), // 1 request per 5 seconds
)
// Set custom timeout
customHTTPClient := &http.Client{
Timeout: 60 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
DisableCompression: true,
},
}
client.SetClient(customHTTPClient)
Error Handling and Retries
client := cwe.NewHttpClient(
cwe.WithMaxRetries(3),
cwe.WithRetryInterval(time.Second),
)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
resp, err := client.Get(ctx, "https://unreliable-api.example.com/data")
if err != nil {
switch {
case strings.Contains(err.Error(), "context deadline exceeded"):
fmt.Println("Request timed out")
case strings.Contains(err.Error(), "达到最大重试次数"):
fmt.Println("Max retries reached")
case strings.Contains(err.Error(), "connection refused"):
fmt.Println("Connection failed")
default:
fmt.Printf("Unknown error: %v\n", err)
}
return
}
defer resp.Body.Close()
Rate Limiting Management
client := cwe.NewHttpClient()
// Get current rate limiter
limiter := client.GetRateLimiter()
fmt.Printf("Current interval: %v\n", limiter.GetInterval())
// Adjust rate limiting based on response
for i := 0; i < 10; i++ {
resp, err := client.Get(context.Background(), "https://api.example.com/data")
if err != nil {
// Slow down on errors
currentInterval := limiter.GetInterval()
limiter.SetInterval(currentInterval * 2)
continue
}
defer resp.Body.Close()
if resp.StatusCode == 429 { // Too Many Requests
// Increase delay
currentInterval := limiter.GetInterval()
limiter.SetInterval(currentInterval * 2)
} else if resp.StatusCode == 200 {
// Gradually speed up on success
currentInterval := limiter.GetInterval()
if currentInterval > time.Second {
limiter.SetInterval(currentInterval / 2)
}
}
}
Concurrent Usage
client := cwe.NewHttpClient()
defer client.Close()
// Client is thread-safe
var wg sync.WaitGroup
urls := []string{
"https://api.example.com/endpoint1",
"https://api.example.com/endpoint2",
"https://api.example.com/endpoint3",
}
for _, url := range urls {
wg.Add(1)
go func(u string) {
defer wg.Done()
resp, err := client.Get(context.Background(), u)
if err != nil {
log.Printf("Failed to fetch %s: %v", u, err)
return
}
defer resp.Body.Close()
fmt.Printf("Fetched %s: %d\n", u, resp.StatusCode)
}(url)
}
wg.Wait()
Performance Considerations
- Rate Limiting: Default 10-second intervals may be slow for high-throughput scenarios
- Retry Logic: Failed requests increase total response time
- Memory Usage: Request bodies are buffered in memory for retries
- Connection Pooling: Uses Go's default HTTP transport connection pooling
Thread Safety
- ✅ All Methods: Thread-safe, can be called concurrently
- ✅ Rate Limiter: Protected by internal mutex
- ✅ Configuration: Safe to modify during operation
- ✅ Concurrent Requests: Supported with shared rate limiting