عميل HTTP بلغة Go: إجراء الطلبات بشكل صحيح (المستوى المتقدم)
توفر الحزمة المدمجة net/http في Go إمكانيات قوية، ولكن غالبًا ما يتم التقليل من شأنها، لإنشاء عملاء HTTP موثوقين. على المستوى الأساسي، يستخدم المطورون http.Get أو http.Post، وهو أمر مناسب للنماذج الأولية السريعة، ولكنه غير مناسب تمامًا للإنتاج. في هذه المقالة، سنستعرض التقنيات المتقدمة لتكوين عميل HTTP بلغة Go: الضبط الدقيق للمهلات، إدارة مجمع الاتصالات، إنشاء سلاسل الوسيطة (middleware)، تنفيذ إعادة المحاولة، ومعالجة الأخطاء بكفاءة. ستتعلم كتابة كود عميل يتحمل الأحمال العالية ويكون مقاومًا للأعطال الشبكية.
1. ضبط المهلات ومجمع الاتصالات
الخطأ الأساسي هو استخدام http.DefaultClient. فهو لا يحتوي على مهلات، ويمكن أن يعلق إلى أجل غير مسمى. للإنتاج، قم دائمًا بإنشاء نسختك الخاصة من http.Client مع ضبط دقيق لـ http.Transport.
package main
import ( "net/http" "time")
func NewClient() *http.Client { transport := &http.Transport{ MaxIdleConns: 100, // الحد الأقصى لاتصالات الخمول في المجمع بأكمله MaxConnsPerHost: 10, // الحد الأقصى للاتصالات لمضيف واحد MaxIdleConnsPerHost: 5, // الحد الأقصى لاتصالات الخمول لمضيف واحد IdleConnTimeout: 90 * time.Second, // عمر اتصال الخمول DisableCompression: false, // تفعيل الضغط (gzip) }
client := &http.Client{ Transport: transport, Timeout: 30 * time.Second, // مهلة إجمالية للطلب بأكمله } return client}دعنا نحلل المعلمات الرئيسية:
- Timeout — الحد الزمني الإجمالي لتنفيذ الطلب (بما في ذلك قراءة نص الاستجابة). قم بتعيينه بناءً على السرعة المتوقعة لواجهة API (عادةً 10-30 ثانية).
- MaxIdleConns — عدد اتصالات keep-alive المخزنة في المجمع. للأنظمة عالية التحميل، قم بزيادته إلى 200-500.
- MaxConnsPerHost — يحد من عدد الاتصالات المتزامنة لمضيف واحد. يمنع التحميل الزائد على الخادم.
يوصى أيضًا بتعيين DialContext بمهلة خاصة لإنشاء الاتصال:
transport.DialContext = (&net.Dialer{ Timeout: 5 * time.Second, // مهلة المصافحة TCP KeepAlive: 30 * time.Second, // Keep-alive للحفاظ على الاتصال}).DialContext2. إنشاء سلاسل الوسيطة (middleware) لعميل HTTP
لا تحتوي Go على وسيطة مدمجة للعميل، ولكن يمكننا بسهولة تنفيذ نمط "المزخرف" (decorator) من خلال تغليف http.RoundTripper. يتيح ذلك إضافة التسجيل، المقاييس، المصادقة، والوظائف الشاملة الأخرى.
type LoggingRoundTripper struct { Proxied http.RoundTripper}
func (l *LoggingRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) { start := time.Now() resp, err := l.Proxied.RoundTrip(r) duration := time.Since(start)
log.Printf("[%s] %s %s - %d (%v)", r.Method, r.URL.String(), r.Host, resp.StatusCode, duration, ) return resp, err}
// الاستخدام:transport := &LoggingRoundTripper{ Proxied: http.DefaultTransport,}client := &http.Client{Transport: transport}يمكنك إنشاء سلسلة من الوسيطة، على سبيل المثال، لإضافة رؤوس المصادقة:
type AuthRoundTripper struct { Proxied http.RoundTripper Token string}
func (a *AuthRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) { r.Header.Set("Authorization", "Bearer "+a.Token) return a.Proxied.RoundTrip(r)}
// السلسلة: Auth → Logging → Transportclient := &http.Client{ Transport: &LoggingRoundTripper{