Menu
Coddy logo textTech

הממשק http.Handler

חלק מהיחידה תכנות מונחה עצמים במסלול ה-GO של Coddy. שיעור 77 מתוך 107.

הממשק http.Handler הוא הבסיס לארכיטקטורת שרת האינטרנט של Go. הוא מגדיר כיצד בקשות HTTP מעובדות, וכל טיפוס שמממש אותו יכול לשרת בקשות אינטרנט.

הממשק פשוט להפליא:

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

כל טיפוס עם מתודה ServeHTTP יכול לטפל בבקשות HTTP. הנה מטפל מותאם אישית:

type GreetHandler struct {
    Greeting string
}

func (h GreetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "%s, visitor!", h.Greeting)
}

אפשר להשתמש במטפל הזה ישירות עם שרת:

handler := GreetHandler{Greeting: "Welcome"}
http.Handle("/greet", handler)

למקרים פשוטים יותר, Go מספקת את http.HandlerFunc, טיפוס שמאפשר לך להמיר פונקציה רגילה למטפל:

func hello(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello!")
}

http.Handle("/hello", http.HandlerFunc(hello))

העוצמה של הממשק הזה מתבהרת כשמבינים שמטפלים יכולים לעטוף מטפלים אחרים. כך מתאפשרים דפוסי תווכה שבהם מוסיפים רישום ביומן, אימות או היבטים רוחביים אחרים בלי לשנות את הלוגיקה המקורית של המטפל.

challenge icon

אתגר

קל

בואו נבנה מערכת פשוטה של מטפלי HTTP שמדמה את אופן העיבוד של בקשות אינטרנט! מכיוון שאי אפשר להריץ שרת HTTP אמיתי בסביבה הזו, תיצרו מטפלים שמממשים את הממשק http.Handler ותדגימו איך הם מעבדים בקשות באמצעות אובייקטים מדומים של בקשה/תגובה.

תארגנו את הקוד בשני קבצים:

  • handlers.go: הגדירו את מטפלי ה-HTTP המותאמים אישית שלכם.

    צרו מבנה MockResponseWriter שמתעד מה היה נכתב לתגובת HTTP. עליו לשמור את גוף התגובה כמחרוזת ולממש מתודה Write(data []byte) (int, error) שמוסיפה נתונים לגוף. הוסיפו מתודה Body() string כדי לקבל את התגובה המצטברת.

    צרו מבנה MockRequest עם שדות מחרוזת Path ו-Method כדי לדמות בקשת HTTP.

    כעת צרו שני מבני מטפל שמממשים את תבנית הממשק http.Handler (עם מתודה ServeHTTP שמקבלת *MockResponseWriter ו-*MockRequest):

    • WelcomeHandler עם שדה Message — כותב את ההודעה ולאחריה את נתיב הבקשה
    • MethodHandler — כותב תגובות שונות בהתאם לשיטת הבקשה: "Fetching data" עבור GET, "Creating resource" עבור POST, ו-"Method not supported" עבור כל דבר אחר
  • main.go: עבדו בקשות באמצעות המטפלים שלכם.

    קראו סוג מטפל (welcome או method), ואז קראו את פרטי הבקשה. עבור מטפל הברכה, קראו גם את הודעת הברכה.

    צרו את המטפל המתאים, בנו בקשה מדומה וקראו ל-ServeHTTP כדי לעבד אותה. הדפיסו את גוף התגובה.

הקלטים הבאים יסופקו:

  • שורה 1: סוג המטפל (welcome או method)
  • שורה 2: נתיב הבקשה
  • שורה 3: שיטת הבקשה
  • שורה 4 (רק עבור welcome): הודעת הברכה

לדוגמה, עבור הקלט:

welcome
/home
GET
Hello from

הפלט שלכם צריך להיות:

Hello from /home

ועבור הקלט:

method
/api/users
POST

הפלט שלכם צריך להיות:

Creating resource

ועבור הקלט:

method
/api/data
GET

הפלט שלכם צריך להיות:

Fetching data

ועבור הקלט:

method
/api/items
DELETE

הפלט שלכם צריך להיות:

Method not supported

האתגר הזה מדגים את הרעיון המרכזי של הממשק http.Handler: כל טיפוס שיש לו מתודה ServeHTTP יכול לטפל בבקשות. ביישומים אמיתיים, http.ResponseWriter ו-*http.Request מגיעים מספריית התקן של Go, אבל דפוס המימוש של המטפלים נשאר בדיוק אותו הדבר.

נסו בעצמכם

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// קרא את סוג המטפל
	scanner.Scan()
	handlerType := scanner.Text()
	
	// קרא את נתיב הבקשה
	scanner.Scan()
	path := scanner.Text()
	
	// קרא את שיטת הבקשה
	scanner.Scan()
	method := scanner.Text()
	
	// צור בקשה מדומה
	request := &MockRequest{
		Path:   path,
		Method: method,
	}
	
	// צור כותב תגובה מדומה
	response := &MockResponseWriter{}
	
	// TODO: על סמך handlerType, צור את המטפל המתאים
	// אם handlerType הוא "welcome", קרא את הודעת הפתיחה וצור WelcomeHandler
	// אם handlerType הוא "method", צור MethodHandler
	// קרא ל-ServeHTTP של המטפל עם response ו-request
	
	if handlerType == "welcome" {
		scanner.Scan()
		message := scanner.Text()
		// TODO: צור WelcomeHandler עם ההודעה וקרא ל-ServeHTTP
		_ = message // הסר שורה זו בעת המימוש
	} else if handlerType == "method" {
		// TODO: צור MethodHandler וקרא ל-ServeHTTP
	}
	
	// הדפס את גוף התגובה
	fmt.Println(response.Body())
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Go אונליין