Hiểu Trọn Bộ `net/http` Trong Golang
Đây là bài viết tổng hợp toàn bộ kiến thức nền tảng về net/http trước khi bạn tìm hiểu về ServeMux/router.
Nếu bạn đọc đến cuối mà không hiểu, hãy đổ lỗi cho… người gõ phím, không phải bạn.
Mục tiêu của bài blog
Sau bài này, bạn sẽ hiểu:
- Handler interface thực chất là cái gì mà ai cũng nhắc.
- Tại sao một kiểu dữ liệu nhìn ngố như
type hotdog intlại có thể trở thành web server. - Request chứa những gì (spoiler: rất nhiều).
- ResponseWriter là cái gì và vì sao nó có quyền năng gửi data về trình duyệt.
- Form data đi vào đâu, tại sao phải
ParseForm(). - Preview nhỏ về ServeMux – router chính thức của Go.
1. Vũ trụ Go Web bắt đầu từ… Handler Interface
Chỉ một dòng:
ServeHTTP(w http.ResponseWriter, r *http.Request)
Bất kỳ type nào có method y chang dòng phía trên đều trở thành… Handler.
Ví dụ:
type hotdog int
func (h hotdog) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hotdog server is serving 🔥")
}
Từ giờ, hotdog trở thành server hợp lệ.
var d hotdog
http.ListenAndServe(":8080", d)
Bạn vừa chạy một web server… bằng hotdog.
Không đùa đâu.
2. ServeHTTP – Luật chơi của Web
Một server có 2 nhiệm vụ:
- Nhận request
- Trả response
Thế nên tham số của phương thức ServeHTTP vô cùng logic:
r *http.Request: thông tin mà client gửi lênw http.ResponseWriter: nơi bạn ghi nội dung để trả về
Hết.
3. *http.Request — Kho báu dữ liệu người dùng gửi lên
Request là một struct rất lớn.
Nó có rất nhiều trường — đủ để viết tiểu thuyết 7 chương.
Những trường quan trọng bạn cần nhớ:
Method
r.Method // GET, POST…
URL
r.URL.Path
r.URL.RawQuery
Header
r.Header.Get("User-Agent")
ContentLength
r.ContentLength
Form Data
Để lấy dữ liệu từ form, bạn phải:
r.ParseForm()
Sau đó:
r.Form // map[string][]string — gồm cả URL query + POST body
r.PostForm // chỉ từ POST body
Hoặc tiện hơn:
r.FormValue("fname") // trả về giá trị đầu tiên
4. URL Values – Kiểu dữ liệu "đa nhân cách"
Cả Form, PostForm, URL.Query() đều có kiểu:
map[string][]string
Tức là:
- Key → tên biến
- Value → slice chứa nhiều giá trị
Ví dụ người dùng submit 2 giá trị cho cùng 1 field:
fname=Todd&fname=James
Bạn sẽ nhận được:
map["fname"] = []string{"Todd", "James"}
Nhìn quen không?
Đúng, nó giống y hệt cách HTML hoạt động.
5. ResponseWriter — Ông vua trả dữ liệu về trình duyệt
ResponseWriter có ba “siêu năng lực”:
Đặt header
w.Header().Set("Content-Type", "text/html")
Gửi status code
w.WriteHeader(200)
Lưu ý: gọi WriteHeader trước khi ghi body.
Nếu không bạn sẽ gặp lỗi “header already written”.
Ghi body về client
fmt.Fprintln(w, "<h1>Hello World</h1>")
Thế là xong.
6. Tổng hợp: Một handler hoàn chỉnh sẽ trông như sau
type hotdog int
func (h hotdog) ServeHTTP(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
w.Header().Set("Content-Type", "text/html")
fmt.Fprintln(w, "<h1>Information</h1>")
fmt.Fprintf(w, "Method: %s<br>", r.Method)
fmt.Fprintf(w, "URL Path: %s<br>", r.URL.Path)
fmt.Fprintf(w, "Form values: %v<br>", r.Form)
}
Chạy:
var d hotdog
http.ListenAndServe(":8080", d)
7. Preview: ServeMux – Router "xịn" sắp xuất hiện
mux := http.NewServeMux()
mux.HandleFunc("/", home)
mux.HandleFunc("/about", about)
http.ListenAndServe(":8080", mux)
Lý do mux có thể truyền vào ListenAndServe?
Vì ServeMux… cũng implement:
ServeHTTP(w http.ResponseWriter, r *http.Request)
Nó cũng là Handler!
Cả thế giới Go Web xoay quanh đúng interface này.
8. Kết luận
Sau bài này, bạn phải nắm rõ:
- Handler interface = vua của web server trong Go.
- Request chứa rất nhiều dữ liệu hữu ích.
- ResponseWriter là cách bạn “nói chuyện” với browser.
- ParseForm là bắt buộc trước khi đọc form data.
- Form → cả URL + body
PostForm → chỉ body - ServeMux (router) cũng là Handler.
Bạn đã có 90% nền tảng để viết web server Go chuyên nghiệp.
Phần tiếp theo sẽ là cuộc cách mạng:
Routing, ServeMux, HandlerFunc, middleware…
Hứa hẹn rất thú vị.
All rights reserved