مقدمة: لماذا من المهم إتقان العمل مع HTTP في Go
\nGo (Golang) هي لغة مصممة للعمل في الشبكات. توفر مكتبتها القياسية net/http أدوات قوية ومرنة لإنشاء كل من الخوادم والعملاء. ومع ذلك، يرتكب العديد من المطورين، خاصة القادمين من لغات البرمجة النصية، أخطاء نموذجية: ينسون إغلاق جسم الاستجابة، ولا يحددون مهلات، أو يعالجون الأخطاء بشكل غير صحيح.
في هذه المقالة، سنقوم بتحليل إنشاء عميل HTTP في Go "من الألف إلى الياء". ستتعلم كيفية إرسال طلبات GET و POST بشكل صحيح، وإدارة الرؤوس، وضبط المهلات، ومعالجة الأخطاء. جميع أمثلة الكود جاهزة للاستخدام.
\n\n1. الأساسيات: إنشاء عميل وأول طلب GET
\nفي Go، عميل HTTP هو هيكل http.Client. يمكنك استخدام العميل العام http.DefaultClient أو إنشاء عميل خاص بك مع إعدادات مخصصة. لنبدأ بطلب GET بسيط.
package main\n\nimport (\n "fmt"\n "io"\n "net/http"\n "os"\n)\n\nfunc main() {\n // استخدام العميل المدمج\n resp, err := http.Get("https://api.example.com/data")\n if err != nil {\n fmt.Printf("خطأ في الطلب: %v\\n", err)\n os.Exit(1)\n }\n defer resp.Body.Close() // هام: أغلق جسم الاستجابة دائمًا!\n\n // قراءة جسم الاستجابة\n body, err := io.ReadAll(resp.Body)\n if err != nil {\n fmt.Printf("خطأ في قراءة الاستجابة: %v\\n", err)\n os.Exit(1)\n }\n\n fmt.Printf("الحالة: %s\\n", resp.Status)\n fmt.Printf("الجسم: %s\\n", string(body))\n}\nالنقاط الرئيسية:
\n- \n
- أغلق
resp.Bodyدائمًا باستخدامdefer. وإلا سيحدث تسرب للموارد (لن تعود الاتصالات إلى المجموعة). \n - تحقق من حالة الاستجابة (
resp.StatusCode). الكود 200 ليس النجاح الوحيد (هناك 201، 204، إلخ). \n io.ReadAllيقرأ الجسم بالكامل في الذاكرة. للاستجابات الكبيرة، استخدمio.Copyأو المعالجة التدفقية. \n
2. عميل متقدم: المهلات والرؤوس والإعدادات المخصصة
\nالعميل العام ليس لديه مهلات افتراضية - وهذا قد يؤدي إلى تجميد البرنامج. أنشئ عميلك الخاص دائمًا مع الإعدادات.
\n2.1. إنشاء عميل بمهلة
\nclient := &http.Client{\n Timeout: 10 * time.Second, // مهلة إجمالية للطلب بأكمله\n}\n\nresp, err := client.Get("https://api.example.com/data")\nيمكنك أيضًا ضبط المهلات على مستويات مختلفة من خلال Transport:
transport := &http.Transport{\n DialContext: (&net.Dialer{\n Timeout: 5 * time.Second, // مهلة الاتصال\n KeepAlive: 30 * time.Second,\n }).DialContext,\n TLSHandshakeTimeout: 5 * time.Second,\n ResponseHeaderTimeout: 5 * time.Second,\n}\n\nclient := &http.Client{\n Transport: transport,\n Timeout: 15 * time.Second,\n}\n\n2.2. إضافة الرؤوس والمعاملات
\nللطلبات المعقدة، استخدم http.NewRequest:
req, err := http.NewRequest("GET", "https://api.example.com/search", nil)\nif err != nil {\n log.Fatal(err)\n}\n\n// إضافة الرؤوس\nreq.Header.Set("Authorization", "Bearer your-token")\nreq.Header.Set("Accept", "application/json")\n\n// إضافة معاملات الاستعلام\nq := req.URL.Query()\nq.Add("query", "golang")\nq.Add("page", "1")\nreq.URL.RawQuery = q.Encode()\n\nresp, err := client.Do(req)\n\n3. العمل مع POST والطرق الأخرى (JSON، النماذج)
\nتتطلب طلبات POST إرسال جسم. سننظر في تنسيقين شائعين: JSON والنموذج المشفر بعنوان URL.
\n3.1. POST مع JSON
\ntype RequestData struct {\n Name string `json:"name"`\n Email string `json:"email"`\n}\n\ndata := RequestData{\n Name: "إيفان",\n Email: "ivan@example.com",\n}\n\njsonData, err := json.Marshal(da