Menu
CoddyTech

interface http.Handler

Thuộc phần Lập trình hướng đối tượng trong hành trình GO của Coddy. Bài học 77 trên 107.

Giao diện http.Handler là nền tảng của kiến trúc máy chủ web trong Go. Giao diện này xác định cách xử lý các yêu cầu HTTP, và mọi kiểu dữ liệu triển khai giao diện này đều có thể phục vụ các yêu cầu web.

Giao diện này vô cùng đơn giản:

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

Bất kỳ kiểu nào có phương thức ServeHTTP đều có thể xử lý yêu cầu HTTP. Đây là một handler tùy chỉnh:

type GreetHandler struct {
    Greeting string
}

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

Bạn có thể dùng bộ xử lý này trực tiếp với máy chủ:

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

Với những trường hợp đơn giản hơn, Go cung cấp http.HandlerFunc, một kiểu cho phép bạn chuyển một hàm thông thường thành một bộ xử lý:

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

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

Bạn sẽ thấy rõ sức mạnh của giao diện này khi nhận ra rằng các trình xử lý có thể bao bọc những trình xử lý khác. Nhờ đó, bạn có thể áp dụng các mẫu middleware để thêm chức năng ghi nhật ký, xác thực hoặc các mối quan tâm xuyên suốt khác mà không cần sửa đổi logic của trình xử lý ban đầu.

challenge icon

Thử thách

Dễ

Hãy cùng xây dựng một hệ thống bộ xử lý HTTP đơn giản mô phỏng cách xử lý các yêu cầu web! Vì không thể chạy máy chủ HTTP thực tế trong môi trường này, bạn sẽ tạo các bộ xử lý triển khai giao diện http.Handler và minh họa cách chúng xử lý yêu cầu bằng cách làm việc với các đối tượng yêu cầu và phản hồi giả lập.

Bạn sẽ sắp xếp code trong hai tệp:

  • handlers.go: Định nghĩa các bộ xử lý HTTP tùy chỉnh.

    Tạo một cấu trúc MockResponseWriter để ghi lại nội dung sẽ được ghi vào phản hồi HTTP. Cấu trúc này cần lưu phần thân phản hồi dưới dạng chuỗi và triển khai phương thức Write(data []byte) (int, error) để nối dữ liệu vào phần thân. Thêm phương thức Body() string để lấy phần phản hồi đã tích lũy.

    Tạo cấu trúc MockRequest với các trường chuỗi Path và Method để mô phỏng một yêu cầu HTTP.

    Bây giờ, hãy tạo hai cấu trúc bộ xử lý triển khai theo mẫu giao diện http.Handler (có phương thức ServeHTTP nhận *MockResponseWriter và *MockRequest):

    • WelcomeHandler có trường Message, ghi thông điệp, sau đó là đường dẫn yêu cầu
    • MethodHandler, ghi các phản hồi khác nhau tùy theo phương thức yêu cầu: "Fetching data" cho GET, "Creating resource" cho POST và "Method not supported" cho mọi trường hợp khác
  • main.go: Xử lý yêu cầu thông qua các bộ xử lý.

    Đọc loại bộ xử lý (welcome hoặc method), sau đó đọc thông tin chi tiết về yêu cầu. Với bộ xử lý welcome, hãy đọc thêm thông điệp chào mừng.

    Tạo bộ xử lý phù hợp, tạo yêu cầu giả lập và gọi ServeHTTP để xử lý yêu cầu. In phần thân phản hồi ra.

Chương trình sẽ nhận các đầu vào sau:

  • Dòng 1: Loại bộ xử lý (welcome hoặc method)
  • Dòng 2: Đường dẫn yêu cầu
  • Dòng 3: Phương thức yêu cầu
  • Dòng 4 (chỉ với welcome): Thông điệp chào mừng

Ví dụ, với đầu vào:

welcome
/home
GET
Hello from

Đầu ra của bạn sẽ là:

Hello from /home

Và với đầu vào:

method
/api/users
POST

Đầu ra của bạn sẽ là:

Creating resource

Và với đầu vào:

method
/api/data
GET

Đầu ra của bạn sẽ là:

Fetching data

Và với đầu vào:

method
/api/items
DELETE

Đầu ra của bạn sẽ là:

Method not supported

Thử thách này minh họa khái niệm cốt lõi của giao diện http.Handler: bất kỳ kiểu nào có phương thức ServeHTTP đều có thể xử lý yêu cầu. Trong ứng dụng thực tế, http.ResponseWriter và *http.Request đến từ thư viện chuẩn của Go, nhưng mẫu triển khai bộ xử lý vẫn hoàn toàn giống như vậy.

Tự làm thử

package main

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

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Đọc loại trình xử lý
	scanner.Scan()
	handlerType := scanner.Text()
	
	// Đọc đường dẫn của yêu cầu
	scanner.Scan()
	path := scanner.Text()
	
	// Đọc phương thức của yêu cầu
	scanner.Scan()
	method := scanner.Text()
	
	// Tạo yêu cầu mô phỏng
	request := &MockRequest{
		Path:   path,
		Method: method,
	}
	
	// Tạo bộ ghi phản hồi mô phỏng
	response := &MockResponseWriter{}
	
	// TODO: Dựa vào handlerType, tạo trình xử lý phù hợp
	// Nếu handlerType là "welcome", đọc thông điệp chào mừng và tạo WelcomeHandler
	// Nếu handlerType là "method", tạo MethodHandler
	// Gọi ServeHTTP trên trình xử lý với response và request
	
	if handlerType == "welcome" {
		scanner.Scan()
		message := scanner.Text()
		// TODO: Tạo WelcomeHandler với thông điệp rồi gọi ServeHTTP
		_ = message // Xóa dòng này khi triển khai
	} else if handlerType == "method" {
		// TODO: Tạo MethodHandler rồi gọi ServeHTTP
	}
	
	// In ra nội dung phản hồi
	fmt.Println(response.Body())
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Go online