مقدمة: لماذا يستحق عميل HTTP في Go الاهتمام
تطبيقات الويب الحديثة نادراً ما تعمل بمعزل عن الآخرين. تقريباً أي خدمة تتفاعل مع واجهات برمجة التطبيقات الخارجية أو الخدمات المصغرة أو الموارد الخارجية عبر HTTP. توفر لغة Go (Golang) مكتبة مدمجة وقوية net/http تتيح إنشاء عملاء HTTP فعالين وعاليي الأداء دون الحاجة إلى تبعيات خارجية.
في هذه المقالة، سنشرح كيفية العمل بشكل صحيح مع عميل HTTP في Go: من طلبات GET البسيطة إلى معالجة الأخطاء وإدارة المهلات الزمنية. ستتعلم كيفية تجنب الأخطاء الشائعة وكتابة كود موثوق.
أساسيات العمل مع عميل HTTP في Go
تم تصميم مكتبة net/http في Go مع مراعاة الأداء. على عكس العديد من اللغات الأخرى حيث ينشئ كل طلب اتصالاً جديداً، يستخدم Go مجموعة اتصالات (connection pool) افتراضياً. هذا يعني أن اتصالات TCP يُعاد استخدامها، مما يسرع العمل بشكل كبير.
أبسط طلب GET
لنبدأ بأبسط مثال — إرسال طلب GET باستخدام الدالة http.Get():
package main
import ( "fmt" "io" "net/http" "os")
func main() { // طلب GET بسيط resp, err := http.Get("https://api.github.com") if err != nil { fmt.Printf("خطأ أثناء تنفيذ الطلب: %v", err) os.Exit(1) } defer resp.Body.Close()
// قراءة نص الرد body, err := io.ReadAll(resp.Body) if err != nil { fmt.Printf("خطأ أثناء قراءة الرد: %v", err) os.Exit(1) }
fmt.Printf("الحالة: %s", resp.Status) fmt.Printf("نص الرد: %s", string(body))}هام: أغلق دائماً نص الرد (resp.Body.Close()). استخدم defer للإغلاق المضمون، حتى في حالة حدوث خطأ.
طلب GET مع معاملات ورؤوس
للطلبات الأكثر تعقيداً، من الأفضل استخدام الصيغة الكاملة مع إنشاء كائن http.Request:
package main
import ( "fmt" "io" "net/http" "time")
func main() { // إنشاء عميل جديد client := &http.Client{ Timeout: 10 * time.Second, }
// إنشاء طلب req, err := http.NewRequest("GET", "https://api.example.com/users", nil) if err != nil { fmt.Printf("خطأ في إنشاء الطلب: %v", err) return }
// إضافة رؤوس req.Header.Set("Authorization", "Bearer your-token-here") req.Header.Set("Accept", "application/json") req.Header.Set("User-Agent", "Go-http-client/1.0")
// إضافة معاملات الاستعلام q := req.URL.Query() q.Add("limit", "10") q.Add("offset", "0") req.URL.RawQuery = q.Encode()
// تنفيذ الطلب resp, err := client.Do(req) if err != nil { fmt.Printf("خطأ في تنفيذ الطلب: %v", err) return } defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body) fmt.Printf("الرد: %s", string(body))}العمل مع طلبات POST و JSON
طلبات POST مع نص JSON هي مهمة قياسية عند العمل مع REST API. توفر Go أدوات مناسبة لتسلسل البيانات.
إرسال JSON باستخدام POST
package main
import ( "bytes" "encoding/json" "fmt" "net/http" "time")
type User struct { Name string `json:"name"` Email string `json:"email"` Age int `json:"age"`}
func main() { user := User{ Name: "إيفان بيتروف", Email: "ivan@example.com", Age: 30, }
// تسلسل الهيكل إلى JSON jsonData, err := json.Marshal(user) if err != nil { fmt.Printf("خطأ في تسلسل JSON: %v", err) return }
client := &http.Client{Timeout: 5 * time.Second}