Go: عملاء HTTP والبرمجيات الوسيطة
آخر تحديث: 2026-08-26
تُعد عملاء HTTP والبرامج الوسيطة حجرَي الزاوية في اتصال الخدمات الصغيرة — حيث يتولى أحدهما إدارة الاتصالات، بينما يتولى الآخر معالجة القضايا المشتركة.
عندما تحتاج خدمتك إلى استدعاء خمس خدمات أخرى تابعة لها، فإن كل استدعاء يتطلب التسجيل، ومعالجة انتهاء المهلة، وإعادة المحاولة، وقطع الدائرة — فهل يجب عليك كتابة هذا الكود خمس مرات أم تجريده مرة واحدة؟ في هذا الدرس، ستتقن الاستخدام المتقدم لعميل HTTP في لغة Go وأنماط تصميم البرمجيات الوسيطة.
1. ستتعلم
http.Get/Post/Doالطلبات الأساسيةhttp.Clientالتحكم في مهلة الانتظارhttp.Transportتكوين مجموعة الاتصالات- نمط البرمجيات الوسيطة (نموذج البصل)
- برامج الوسيطة الشائعة: التسجيل، الاستعادة، CORS، مهلة الانتظار
httputil.ReverseProxyالوكيل العكسي
2. قصة حقيقية لمهندس برمجيات الخلفية
(1) المشكلة: خمس خدمات لاحقة، تتطلب كل منها تسجيل الأحداث، ومعالجة انتهاء المهلة، وإعادة المحاولة
تشارلي مسؤول عن خدمة بوابة واجهة برمجة التطبيقات (API) الخاصة بالشركة، والتي تحتاج إلى استدعاء خمس خدمات تابعة:
«يجب أن تقوم كل مكالمة لاحقة بما يلي: طباعة سجل الطلب (لتسهيل استكشاف الأخطاء وإصلاحها)، وتعيين مهلة (لمنع حدوث حالات التعطل)، وتسجيل المدة (لأغراض المراقبة والتنبيهات). انتهى بي الأمر إلى كتابة نفس الكود خمس مرات — دالة واحدة لكل خدمة، تحتوي كل منها على نفس «التركيبة» المتكررة المكونة من التسجيل، والمهلة، والمكالمة نفسها.»
الكود الذي كان يستخدمه في ذلك الوقت:
// Bad code: every downstream service repeats the same logic
func callUserService(w http.ResponseWriter, r *http.Request) {
log.Printf("[%s] Requesting user service: %s", r.Method, r.URL.Path)
start := time.Now()
resp, err := http.Get("http://user-service/api/users")
log.Printf("[%s] User service elapsed: %v", r.Method, time.Since(start))
// ... process response
}
func callOrderService(w http.ResponseWriter, r *http.Request) {
log.Printf("[%s] Requesting order service: %s", r.Method, r.URL.Path)
start := time.Now()
resp, err := http.Get("http://order-service/api/orders")
log.Printf("[%s] Order service elapsed: %v", r.Method, time.Since(start))
// ... same pattern again!
}
// Every new service repeats!
(2) حل Go: نمط البرمجيات الوسيطة + عميل مخصص
// Middleware: wraps http.RoundTripper
type LoggingMiddleware struct {
next http.RoundTripper
}
func (m *LoggingMiddleware) RoundTrip(req *http.Request) (*http.Response, error) {
start := time.Now()
log.Printf("[%s] %s %s", req.Method, req.URL.Host, req.URL.Path)
resp, err := m.next.RoundTrip(req)
log.Printf("[%s] %s elapsed: %v", req.Method, req.URL.Path, time.Since(start))
return resp, err
}
// Unified Client: shared by all downstream services
client := &http.Client{
Timeout: 5 * time.Second,
Transport: &LoggingMiddleware{
next: http.DefaultTransport,
},
}
// All downstream calls automatically get logging + timeout
resp1, _ := client.Get("http://user-service/api/users") // Auto logging
resp2, _ := client.Get("http://order-service/api/orders") // Auto logging
(3) الفوائد: قبل وبعد تنفيذ البرمجيات الوسيطة
| البعد | رمز التكرار | نمط البرمجيات الوسيطة |
|---|---|---|
| حجم الكود | 30 سطراً لكل عملية تالية، و5 عمليات تالية = 150 سطراً | 15 سطراً من البرمجيات الوسيطة، ليصبح المجموع 30 سطراً |
| إضافة في المرحلة التالية | نسخ ولصق 30 سطراً | الاتصال بـ client.Get مباشرةً |
| مهلة التحرير | تغيير 5 مواقع | تغيير مهلة عميل واحد |
3. أساسيات عميل HTTP
▶ مثال: GET / POST / الطلبات المخصصة
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
)
func main() {
// 1. GET request
resp, err := http.Get("https://api.example.com/users")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Printf("GET status: %d\n", resp.StatusCode)
fmt.Printf("Response: %s\n", body)
// 2. POST JSON request
data := map[string]string{"name": "Alice"}
jsonData, _ := json.Marshal(data)
resp, err = http.Post(
"https://api.example.com/users",
"application/json",
bytes.NewReader(jsonData),
)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
// 3. Custom request (set Headers)
req, _ := http.NewRequest("DELETE", "https://api.example.com/users/1", nil)
req.Header.Set("Authorization", "Bearer token-123")
req.Header.Set("X-Request-ID", "req-456")
resp, err = http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
fmt.Printf("DELETE status: %d\n", resp.StatusCode)
}
(2) http.Get مقابل http.Client
// Method 1: Use http.Get directly (default Client)
resp, _ := http.Get(url)
// Problem: No default timeout, may hang forever!
// Method 2: Custom Client (recommended)
client := &http.Client{
Timeout: 10 * time.Second,
}
resp, _ := client.Get(url)
// Safe: 10-second timeout auto-cancels
| الطريقة | مهلة الانتظار | تجمع الاتصالات | التوصية |
|---|---|---|---|
http.Get(url) |
بدون مهلة | الإعداد الافتراضي (إعادة استخدام محدودة) | ❌ للاختبار السريع فقط |
http.DefaultClient |
بدون مهلة | الافتراضي | ⚠️ استخدم بحذر في بيئة الإنتاج |
&http.Client{Timeout: 10s} |
المهلة العامة | الافتراضي | ✅ موصى به |
&http.Client{Timeout, Transport} |
المهلة الزمنية العامة | مجموعة اتصالات مخصصة | ✅ جاهز للاستخدام في بيئة الإنتاج |
4. مهلة http.Client والنقل
▶ مثال: تكوين فترات الانتظار ومجموعات الاتصالات
package main
import (
"fmt"
"net"
"net/http"
"time"
)
func main() {
// Custom Transport
transport := &http.Transport{
// Connection pool
MaxIdleConns: 100, // Max idle connections
MaxIdleConnsPerHost: 10, // Max idle connections per host
IdleConnTimeout: 90 * time.Second, // Idle connection timeout
// TLS
TLSHandshakeTimeout: 10 * time.Second,
// Dial
DialContext: (&net.Dialer{
Timeout: 30 * time.Second, // Connection timeout
KeepAlive: 30 * time.Second, // Keep-Alive interval
}).DialContext,
}
// Custom Client
client := &http.Client{
Timeout: 30 * time.Second, // Total request timeout (includes all stages)
Transport: transport,
}
// Use client to send request
resp, err := client.Get("https://api.example.com/users")
if err != nil {
fmt.Printf("Request failed: %v\n", err)
return
}
defer resp.Body.Close()
fmt.Printf("Status: %d\n", resp.StatusCode)
}
▶ مثال: التحكم في مهلة الانتظار المتدرجة
package main
import (
"fmt"
"net"
"net/http"
"time"
)
func main() {
// Timeout tiers:
// Transport.DialContext → Connection timeout (10s)
// Transport.TLSHandshake → TLS handshake timeout (5s)
// Transport.ResponseHeader → Response header timeout (10s)
// Client.Timeout → Total timeout (30s, covers Dial + TLS + send + read)
transport := &http.Transport{
DialContext: (&net.Dialer{
Timeout: 10 * time.Second,
}).DialContext,
TLSHandshakeTimeout: 5 * time.Second,
ResponseHeaderTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
client := &http.Client{
Timeout: 30 * time.Second,
Transport: transport,
}
start := time.Now()
resp, err := client.Get("https://httpbin.org/delay/5")
if err != nil {
fmt.Printf("Error: %v (elapsed: %v)\n", err, time.Since(start))
return
}
defer resp.Body.Close()
fmt.Printf("Success: %d (elapsed: %v)\n", resp.StatusCode, time.Since(start))
}
(3) معلمات تكوين النقل
| المعلمة | القيمة الافتراضية | القيمة الموصى بها | الوصف |
|---|---|---|---|
MaxIdleConns |
100 | 100–200 | الحد الأقصى الإجمالي لعدد الاتصالات الخاملة |
MaxIdleConnsPerHost |
2 | 10–50 | الحد الأقصى لعدد الاتصالات الخاملة لكل مضيف (القيمة الافتراضية 2 منخفضة جدًّا!) |
IdleConnTimeout |
التسعينيات | 30–90 | انتهت مهلة الاتصال في حالة الخمول |
TLSHandshakeTimeout |
10 ثوانٍ | 5–10 ثوانٍ | انتهاء مهلة مصافحة TLS |
ResponseHeaderTimeout |
0 (لم يحدث قط) | 10–30 ثانية | انتهت مهلة رأس الاستجابة |
DialContext.Timeout |
لا شيء | 10–30 ثانية | انتهت مهلة اتصال TCP |
MaxIdleConnsPerHost في http.Transport هي 2 فقط، وهي قيمة غير كافية على الإطلاق في الحالات التي تتضمن مكالمات متزامنة بكثافة إلى نفس الخدمة. تأكد من زيادة هذه القيمة وفقًا لمستوى التزامن (على سبيل المثال، 50–100).
5. نمط البرمجيات الوسيطة
▶ مثال: نموذج «أونيون» للبرمجيات الوسيطة
package main
import (
"context"
"fmt"
"log"
"net/http"
"time"
)
// Middleware type: receives Handler, returns Handler
type Middleware func(http.Handler) http.Handler
// Middleware chain: assembles all middleware into one
func Chain(handler http.Handler, middlewares ...Middleware) http.Handler {
for i := len(middlewares) - 1; i >= 0; i-- {
handler = middlewares[i](handler)
}
return handler
}
// ---------- Concrete middleware ----------
// 1. Logging middleware
func LoggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
log.Printf("[%s] %s %s", r.Method, r.URL.Path, r.RemoteAddr)
next.ServeHTTP(w, r)
log.Printf("[%s] %s elapsed: %v", r.Method, r.URL.Path, time.Since(start))
})
}
// 2. Recovery middleware (prevents panic from crashing the service)
func RecoveryMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
log.Printf("[PANIC] %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
}()
next.ServeHTTP(w, r)
})
}
// 3. CORS middleware
func CORSMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusNoContent)
return
}
next.ServeHTTP(w, r)
})
}
// 4. Timeout middleware
func TimeoutMiddleware(timeout time.Duration) Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), timeout)
defer cancel()
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
// ---------- Usage ----------
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %s!", r.URL.Query().Get("name"))
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /hello", helloHandler)
// Chain all middleware (onion model: Recovery → Logging → CORS → Handler)
handler := Chain(mux,
RecoveryMiddleware,
LoggingMiddleware,
CORSMiddleware,
TimeoutMiddleware(5*time.Second),
)
log.Print(http.ListenAndServe(":8080", handler))
}
graph LR
Req[Request] --> R[Recovery]
R --> L[Logging]
L --> C[CORS]
C --> T[Timeout]
T --> H[Handler]
H -->|Response| T
T --> C
C --> L
L --> R
R --> Resp[Response]
(2) مسؤوليات المكونات الأربعة الأساسية للبرمجيات الوسيطة
| البرامج الوسيطة | المسؤوليات | الترتيب |
|---|---|---|
| الاسترداد | اكتشاف حالة الذعر، إرجاع 500 | Outermost |
| التسجيل | أوقات طلبات التسجيل والاستجابات | الطبقة الثانية |
| CORS | معالجة رؤوس طلبات «عبر المنشأ» | الطبقة الثالثة |
| انتهاء المهلة | التحكم في مهلة الطلب | الطبقة الأعمق (القريبة من المعالج) |
6. httputil.ReverseProxy - الوكيل العكسي
▶ مثال: الوكيل العكسي
package main
import (
"log"
"net/http"
"net/http/httputil"
"net/url"
)
func main() {
// Target service address
target, _ := url.Parse("http://localhost:8081")
// Create reverse proxy
proxy := httputil.NewSingleHostReverseProxy(target)
// Custom Director (modify request headers)
proxy.Director = func(req *http.Request) {
req.URL.Scheme = target.Scheme
req.URL.Host = target.Host
req.URL.Path = target.Path + req.URL.Path
req.Header.Set("X-Forwarded-Host", req.Header.Get("Host"))
req.Header.Set("X-Real-IP", req.RemoteAddr)
}
// Custom error handling
proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
log.Printf("Proxy error: %v", err)
http.Error(w, "Bad Gateway", http.StatusBadGateway)
}
mux := http.NewServeMux()
mux.HandleFunc("/api/", proxy.ServeHTTP)
log.Print("API gateway started on :8080")
log.Fatal(http.ListenAndServe(":8080", mux))
}
httputil.ReverseProxy تلقائيًا معالجة معظم تفاصيل البروكسي: إعادة توجيه رأس المضيف، وX-Forwarded-For، وتمرير رؤوس الاستجابة، وإعادة استخدام مجموعة الاتصالات. كل ما عليك فعله هو توفير دالة Director لتعديل الطلب.
7. مثال كامل: API Gateway + مسار البرمجيات الوسيطة
// api_gateway.go
package main
import (
"context"
"encoding/json"
"log"
"net/http"
"net/http/httputil"
"net/url"
"os"
"os/signal"
"strings"
"time"
)
// ---------- Configuration ----------
type Route struct {
Path string
Target *url.URL
}
type GatewayConfig struct {
Port string
Routes []Route
Middlewares []Middleware
}
// ---------- Middleware ----------
type Middleware func(http.Handler) http.Handler
func Chain(handler http.Handler, middlewares ...Middleware) http.Handler {
for i := len(middlewares) - 1; i >= 0; i-- {
handler = middlewares[i](handler)
}
return handler
}
// Logging
func Logging(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
log.Printf("[%s] %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
log.Printf("[%s] %s → %v", r.Method, r.URL.Path, time.Since(start))
})
}
// Recovery
func Recovery(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
log.Printf("[PANIC] %v", err)
http.Error(w, `{"error":"internal error"}`, http.StatusInternalServerError)
}
}()
next.ServeHTTP(w, r)
})
}
// CORS
func CORS(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusNoContent)
return
}
next.ServeHTTP(w, r)
})
}
// Rate limiting (simplified token bucket)
type RateLimiter struct {
tokens chan struct{}
}
func NewRateLimiter(rate int) *RateLimiter {
rl := &RateLimiter{tokens: make(chan struct{}, rate)}
for i := 0; i < rate; i++ {
rl.tokens <- struct{}{}
}
// Refill every second
go func() {
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for range ticker.C {
select {
case rl.tokens <- struct{}{}:
default:
}
}
}()
return rl
}
func (rl *RateLimiter) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
select {
case <-rl.tokens:
next.ServeHTTP(w, r)
default:
http.Error(w, `{"error":"rate limit exceeded"}`, http.StatusTooManyRequests)
}
})
}
// ---------- Gateway ----------
type Gateway struct {
config GatewayConfig
proxy *httputil.ReverseProxy
}
func NewGateway(config GatewayConfig) *Gateway {
proxy := &httputil.ReverseProxy{
Director: func(req *http.Request) {
// Match route based on request path
for _, route := range config.Routes {
if strings.HasPrefix(req.URL.Path, route.Path) {
req.URL.Scheme = route.Target.Scheme
req.URL.Host = route.Target.Host
req.URL.Path = strings.TrimPrefix(req.URL.Path, route.Path)
req.Header.Set("X-Forwarded-Host", req.Header.Get("Host"))
return
}
}
},
ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
log.Printf("Proxy error: %v", err)
http.Error(w, `{"error":"bad gateway"}`, http.StatusBadGateway)
},
}
return &Gateway{config: config, proxy: proxy}
}
func (g *Gateway) Start() error {
routesJSON, _ := json.MarshalIndent(g.config.Routes, "", " ")
log.Printf("Loading routes:\n%s\n", routesJSON)
// Route distribution
mux := http.NewServeMux()
for _, route := range g.config.Routes {
pattern := route.Path
if !strings.HasSuffix(pattern, "/") {
pattern += "/"
}
mux.Handle(pattern, g.proxy)
}
// Health check
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
})
// Middleware chain
handler := Chain(mux, g.config.Middlewares...)
server := &http.Server{
Addr: ":" + g.config.Port,
Handler: handler,
}
// Graceful shutdown
go func() {
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, os.Interrupt)
<-sigCh
log.Println("Shutting down server...")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
server.Shutdown(ctx)
}()
log.Printf("API gateway started on :%s", g.config.Port)
return server.ListenAndServe()
}
func main() {
userService, _ := url.Parse("http://localhost:8081")
orderService, _ := url.Parse("http://localhost:8082")
config := GatewayConfig{
Port: "8080",
Routes: []Route{
{Path: "/api/users", Target: userService},
{Path: "/api/orders", Target: orderService},
},
}
config.Middlewares = []Middleware{
Recovery,
Logging,
CORS,
}
gateway := NewGateway(config)
if err := gateway.Start(); err != nil && err != http.ErrServerClosed {
log.Fatal(err)
}
}
httputil.ReverseProxy بتعديل رأس X-Forwarded-For بشكل افتراضي. إذا كنت لا ترغب في هذا السلوك، فقم بإزالة الرأس في Director. بالإضافة إلى ذلك، لا يتعامل ReverseProxy تلقائيًا مع ترقيات WebSocket — حيث إن طريقة ServeHTTP في httputil.ReverseProxy لا تدعم WebSockets، لذا يجب عليك التعامل مع طلب الترقية بشكل منفصل.
❓ أسئلة شائعة
http.Get وhttp.Client؟http.Get للاختبار السريع. في بيئة الإنتاج، استخدم دائمًا http.Client المخصص — اضبط Timeout لمنع تعطل الطلبات، وقم بتكوين Transport للتحكم في تجميع الاتصالات وتفاصيل مهلة الانتظار. يستخدم http.Get http.DefaultClient، الذي لا يحتوي على مهلة انتظار افتراضية.IdleConnTimeout على 30–90 ثانية للحفاظ على الاتصالات نشطة.Chain(h, A, B, C) → تمر الطلبات عبر A → B → C → المعالج؛ وتمر الاستجابات عبر C → B → A.Director لتعديل Scheme وHost وPath للطلب. وهي مناسبة كنقطة دخول لحركة المرور في بنى الخدمات الصغيرة.http.Client آمن للاستخدام المتعدد الخيوط؟http.Client بشكل متزامن (لا تتطلب الاستدعاءات المتعددة لـ Get أو Do أقفالًا إضافية). ومع ذلك، لا ينبغي تعديل حقول Transport بعد الاستخدام الأول. أفضل الممارسات: قم بإنشاء Client واحد لكل مجموعة خدمات تابعة؛ ولا تقم بإنشاء Client جديد لكل طلب.http.NewRequest، قم بتعيين الرأس على النحو التالي: req.Header.Set("Key", "Value"). لا تستخدم req.Header.Add("Key", "Value")—Add لأنها تضيف إلى الرؤوس بدلاً من استبدالها. يتم تمرير الرؤوس الشائعة مثل Auth وTraceID وContent-Type جميعها في رؤوس الطلب.📖 ملخص
- الأنواع الثلاثة للطلبات: HTTP GET وPOST وDO
- تعيين مهلة لـ http.Client لمنع تعطلها
- تكوين تجمع اتصالات http.Transport (زيادة قيمة MaxIdleConnsPerHost)
- نمط البرمجيات الوسيطة: نموذج البصل، حيث تنتقل الطلبات من الطبقة الخارجية إلى الطبقة الداخلية
- 4 مكونات أساسية للبرمجيات الوسيطة: الاستعادة → التسجيل → CORS → مهلة الانتظار
- httputil.ReverseProxy يُنفِّذ وظيفة الوكيل العكسي
- تعمل بوابة واجهة برمجة التطبيقات (API Gateway) على دمج سلسلة البرامج الوسيطة مع عمليات التوجيه والتوزيع
📝 تمارين
-
تمرين أساسي (مستوى الصعوبة: ⭐): اكتب
http.Clientمخصصًا بوقت انتظار مدته 5 ثوانٍ وMaxIdleConnsPerHost=20. استخدم هذاClientلإرسال طلب GET إلى https://httpbin.org/delay/3 وتأكد من أن وقت الانتظار يعمل كما هو متوقع. -
مشكلة متقدمة (صعوبة ⭐⭐): قم بتنفيذ برنامج وسيط لإعادة محاولة الطلبات (طبقة RoundTripper). المتطلبات: (1) إعادة محاولة طلبات GET تلقائيًا حتى 3 مرات؛ (2) ضبط فترات إعادة المحاولة على 100 مللي ثانية، و200 مللي ثانية، و400 مللي ثانية، على التوالي (التراجع الأسي)؛ (3) إعادة المحاولة فقط للاستجابات 5xx؛ لا تقم بإعادة المحاولة للاستجابات 4xx؛ (4) تسجيل كل محاولة إعادة.
-
التحدي (الصعوبة: ⭐⭐⭐): قم بتنفيذ وكيل عكسي مع موازنة الحمل. المتطلبات: (1) دعم تسجيل عدة مثيلات للخلفية (على سبيل المثال، 3 مثيلات لخدمة المستخدمين)؛ (2) توزيع الطلبات باستخدام خوارزمية Round-Robin؛ (3) إجراء فحوصات حالة سلبية — إزالة مثيل بعد 3 حالات فشل متتالية وإعادة إضافته بمجرد تعافيه؛ (4) تسجيل عنوان الخلفية الذي يتم توجيه كل طلب إليه؛ (5) التنفيذ باستخدام
httputil.ReverseProxy.