محتويات الدورة

Go / المتوسط: الحزم والعمل المتزامن / الدرس 11

معالجات HTTP والعملاء

ركب سلوك HTTP محدودا واختبر المعالجات دون خدمات خارجية وحدد أعمار الطلب والموارد.

وقت القراءة التقريبي: 4 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • تنفيذ Handler واختبارها مباشرة.
  • استخدام عملاء محدودين وإغلاق الأجسام.
  • فصل حالة HTTP من فشل النقل والتحليل.

المعالج يترجم حد بروتوكول

تتلقى http.Handler كاتب استجابة وطلبا. افحص الطريقة والمسار والنوع والحجم والصياغة والمجال قبل اعتماد استجابة أو أثر خارجي. تعتمد كتابة الجسم حالة ضمنية إن لم تكتب حالة، فحدد الرؤوس والحالة أولا. تنهي عودة المعالج معالجة الطلب لا الخادم كله.

أضافت Go 1.22 أنماط ServeMux الواعية بالطريقة وتغييرات توجيه. يستخدم المثال الأول هذه الميزة عمدا. قد تؤثر إعدادات التوافق والإصدارات الأقدم في السلوك، فحدد الاعتماد ولا تفترض فهم كل تثبيت لنمط يبدأ بالطريقة.

اختبار HTTP دون فتح منفذ

تستدعي httptest.NewRequest وNewRecorder المعالج مباشرة فتفحص التوجيه والحالة والرؤوس والجسم دون خدمة شبكة خارجية. لا تختبر المقابس أو مواعيد النقل أو إيقاف الخادم الفعلي. طابق الطريقة والمسار مع الواجهة وأضف الرفض والمدخل المعيب عند التوسع.

يطبع البرنامج الحالة والجسم مقتبسا فتظهر نهاية السطر. يكتب المعالج استجابة اصطناعية ثابتة ولا يحتفظ بروتينات. افحص request.Context في المعالجات الحقيقية ولا تبدأ عملا خلفيا بلا مالك منفصل العمر.

go معالج صحة يُستدعى مباشرة
package main

import (
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
)

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		_, _ = io.WriteString(w, "ready\n")
	})
	recorder := httptest.NewRecorder()
	mux.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/health", nil))
	fmt.Printf("%d %q\n", recorder.Code, recorder.Body.String())
}
الناتج المتوقع
200 "ready\n"

ينتج المسار الواعي بالطريقة الحالة 200 وجسما من ready ونهاية سطر.

حد عملية العميل وأغلق الجسم

استخدم http.Client قابلا لإعادة الاستخدام بسياسة موعد مقصودة وأرفق السياق بالطلب. لا تعني حالة 404 عادة خطأ نقل من Client.Do؛ افحص StatusCode. أغلق Body في كل مسار بعد الحصول على الاستجابة. ويعتمد استخدام الاتصالات مجددا على استهلاك الجسم بما يلائم سياسة الحجم.

يستخدم المثال التالي خادم اختبار على منفذ محلي مؤقت وعميلا محدودا وموعد طلب وقراءة محدودة وإغلاقا مؤجلا. لا يتصل بخدمة خارجية ويغلق الخادم قبل العودة. تتجنب الاستجابة الصغيرة المعروفة قراءة غير محدودة وتمنح خرجا حتميا.

go رحلة HTTP محلية تغلق نفسها
package main

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"time"
)

func main() {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		_, _ = io.WriteString(w, "hello\n")
	}))
	defer server.Close()
	client := server.Client()
	client.Timeout = 2 * time.Second
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()
	request, err := http.NewRequestWithContext(ctx, http.MethodGet, server.URL, nil)
	if err != nil {
		panic(err)
	}
	response, err := client.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()
	body, err := io.ReadAll(io.LimitReader(response.Body, 33))
	if err != nil || len(body) > 32 || response.StatusCode != http.StatusOK {
		panic("invalid lab response")
	}
	fmt.Printf("%d %q\n", response.StatusCode, string(body))
}
الناتج المتوقع
200 "hello\n"

يعيد خادم المختبر ستة بايتات؛ ويتحقق العميل المحدود من الحالة ويغلق الموارد.

الخدمة تحتاج أكثر من معالج

يحتاج http.Server المنشور قرارات مهلة للرؤوس والقراءة والكتابة والخمول تناسب البروتوكول، وحدود جسم وعمل تابع. قد تكسر مهلة منسوخة البث أو العمليات الطويلة فاشتق الحدود من المتطلبات. رتب إيقافا متدرجا يمنع الجديد وينتظر بسياق تنظيف منفصل محدود.

لا تكشف التنقيح أو التحليل لشبكات غير موثوقة عرضا. اجعل المصادقة والتفويض وحجب التفاصيل حدودا صريحة. لا تتطلب اختبارات المعالج الاصطناعية بيانات اعتماد إنتاج أو قواعد حية. يفحص محول ذاكرة المجال واختبار تكامل النقل منفصلا.

صنف الفشل قبل اختيار الاستجابة

المدخل غير الصالح والمورد الغائب ومهلة الخدمة التابعة وخرق الثابت حالات مختلفة. اربط الفئات بسلوك HTTP ثابت وسجل السياق الداخلي مرة عند مالكه. لا تسرب المكدس أو تفاصيل التخزين في الاستجابة لمجرد أن الخطأ يملك String أو Error.

اختبر رفض الطرق وحدود الجسم والتحليل والإلغاء والتنظيف مع النجاح. قد تكون 200 بعد فشل جزئي مضللة. بعد اعتماد الاستجابة لا يبدل تغيير الحالة اللاحق البايتات المرسلة بأثر رجعي.

الأخطاء الشائعة وإصلاحها

تُعامل 404 كبيانات مجال ناجحة.

لماذا يحدث؟
فُحص خطأ النقل فقط.
كيف تصلحه؟
افحص StatusCode قبل تحليل مخطط النجاح.
كيف تتجنب تكراره؟
اختبر استجابات غير 2xx.

تتراكم الاتصالات بعد الطلبات.

لماذا يحدث؟
لا تغلق أجسام الاستجابة باتساق.
كيف تصلحه؟
أجل الإغلاق فورا بعد الحصول الناجح.
كيف تتجنب تكراره؟
اختبر الفشل بعد وصول الرؤوس.

يحاول معالج تغيير الحالة بعد بدء الخرج.

لماذا يحدث؟
اعتمدت كتابة الجسم الحالة.
كيف تصلحه؟
تحقق أولا واضبط الرأس والحالة قبل الكتابة.
كيف تتجنب تكراره؟
اختبر الاستجابة الأولى المعتمدة لا النص النهائي فقط.

اختبر فهمك

1. صمم اختبار رفض جسم زائد دون الاتصال بخدمة تابعة حقيقية.

اعرض الحل المشروح

استدع المعالج بـhttptest وجسم اصطناعي يزيد بايتا وحقن اعتماد يسجل الاستدعاءات. اشترط حالة الرفض وعدم استدعاء التابع. اختبر الحد الدقيق وتحرير الموارد أيضا. يهم الحد عندما يسبق الرفض أثرا غير مقصود.

2. لماذا لا تحل defer response.Body.Close تخصيص جسم غير محدود؟

اعرض الحل المشروح

يضبط الإغلاق العمر لا كمية الذاكرة. استخدم حد حجم واقرأ الحد زائد واحد لكشف الزائد حيث يلائم وافحص الأخطاء. يحد موعد الطلب الوقت مستقلا. يجب تصميم الحجم والوقت والإغلاق؛ فلا يستلزم أحدها البقية.

أهم ما تعلمته

  • حالة HTTP وخطأ النقل وفشل المجال طبقات منفصلة.
  • حد الوقت والحجم ثم أغلق أجسام الاستجابة.
  • تفحص اختبارات المعالج والخوادم المحلية المؤقتة حدودا مختلفة.

المراجع الرسمية