طلب POST مع JSON بلغة Go: من المبتدئ إلى الإنتاج

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

إرسال JSON في طلب POST بلغة Go: من "كيف يعمل هذا أساساً" إلى "فعلته ونسيته"



هل سبق لك أن علقت في Stack Overflow محاولاً فهم لماذا لا يقبل الخادم طلب POST الخاص بك مع JSON بلغة Go؟ مألوف: يبدو كل شيء صحيحاً، لكن الرد يأتي بـ 400 Bad Request أو نص فارغ. اتضح أن هناك عدة طرق لإرسال JSON في Go، واختيار الطريقة الصحيحة ليس مجرد مسألة ذوق، بل مسألة استقرار الخدمة المصغرة الخاصة بك.



في هذه المقالة، لن نعرض الكود فقط. سنستعرض ثلاثة أساليب: من الساذج (الذي يعمل لكنه خطير) إلى حل جاهز للإنتاج مع معالجة صحيحة للأخطاء والسياقات. إذا كنت تكتب بلغة Go لواجهات API أو البوتات أو التكاملات، فهذه قراءة إلزامية.



لماذا هذا الموضوع شائع جداً؟

Go هي لغة للخدمات الشبكية. عاجلاً أم آجلاً، يواجه أي مطور مهمة: "إرسال JSON في نص طلب POST". قد يبدو الأمر بسيطاً، لكن هناك تفاصيل دقيقة:

  • تحتاج إلى تسلسل الهيكل بشكل صحيح إلى JSON (تعبئة).
  • من المهم ألا تنسى العنوان Content-Type: application/json.
  • من الضروري إغلاق نص الرد بشكل صحيح.
  • نريد تجنب تسرب الذاكرة وحالات الذعر.

دعنا نستعرض كل أسلوب بأمثلة حية.



الأسلوب 1: "على عجالة" — bytes.NewBuffer + json.Marshal

هذه هي أبسط طريقة. نأخذ هيكلاً، نعبئه إلى بايتات، نضعه في مخزن مؤقت ونرسله. العديد من مطوري Go المبتدئين يكتبون بهذه الطريقة.



package main

import ( "bytes" "encoding/json" "fmt" "net/http")

type User struct { Name string `json:"name"` Email string `json:"email"`}

func main() { user := User{Name: "إيفان بيتروف", Email: "ivan@example.com"} // الخطوة 1: تعبئة الهيكل إلى JSON jsonData, err := json.Marshal(user) if err != nil { fmt.Println("خطأ في التعبئة:", err) return } // الخطوة 2: إنشاء طلب POST resp, err := http.Post( "https://api.example.com/users", "application/json", bytes.NewBuffer(jsonData), ) if err != nil { fmt.Println("خطأ في الطلب:", err) return } defer resp.Body.Close() fmt.Println("الحالة:", resp.Status)}


مزايا وعيوب هذا الأسلوب

  • الميزة: أقل كود، مفهوم للمبتدئين.
  • العيب: لا مرونة. لا يمكنك إضافة عناوين مخصصة (مصادقة، trace-id). لا تحكم في المهلات. إذا أعاد الخادم خطأً، فلن تعالجه.
  • العيب: مشكلة محتملة: إذا أعاد json.Marshal خطأً، ستلتقطه، لكن في الكود الحقيقي غالباً ما يُنسى التحقق.

هذه الطريقة مناسبة للنماذج الأولية والاختبارات. للإنتاج — لا.



الأسلوب 2: "الصحيح" — http.NewRequest + json.NewEncoder

يوصي مجتمع Go باستخدام http.NewRequest و json.NewEncoder. لماذا؟ لأنه يعطي تحكماً كاملاً في الطلب وأكثر كفاءة في الذاكرة.



package main

import ( "bytes" "encoding/json" "fmt" "net/http" "time")

type Order struct { ID int `json:"id"` Amount float64 `json:"amount"` Items []string `json:"items"`}

func sendOrder(order Order) error { // إنشاء مخزن مؤقت ومشفر var buf bytes.Buffer enc := json.NewEncoder(&buf) // الترميز مباشرة في المخزن المؤقت (بدون []byte وسيط) if err := enc.Encode(order); err != nil { return fmt.Errorf("خطأ في ترميز JSON: %w", err) } // إنشاء الطلب req, err := http.NewRequest("POST", "https://api.example.com/orders", &buf) if err != nil { return fmt.Errorf("خطأ في إنشاء الطلب: %w", err) } // تعيين العناوين req.Header.Set("Content-Type", "application/json") req.Hea

المدونات

توصيات الكتب