HttpRouter
Địa chỉ repository: julienschmidt/httprouter: A high performance HTTP request router that scales well (github.com)
Thành phần định tuyến của Gin sử dụng HttpRouter, đây cũng là một thành phần định tuyến nhẹ và hiệu suất cao, toàn bộ thành phần chỉ có ba file .go, mã nguồn rất ngắn gọn, chủ yếu có các đặc điểm sau.
Khớp một-một: Một yêu cầu chỉ có thể khớp với không hoặc một định tuyến, và có lợi cho việc tối ưu hóa SEO.
Tự động hiệu chỉnh đường dẫn: Tùy chọn phong cách URL bạn thích, dù thừa hay thiếu một dấu gạch chéo, nó cũng sẽ tự động chuyển hướng. Nếu có lỗi viết hoa/viết thường, nó cũng sẽ bỏ qua chữ hoa/chữ thường để chuyển hướng chính xác.
Tự động phân tích cú pháp tham số định tuyến: Chỉ cần đặt tên cho đoạn đường dẫn, bộ định tuyến sẽ truyền giá trị động cho bạn. Do thiết kế của bộ định tuyến, chi phí phân tích cú pháp tham số đường dẫn rất thấp.
Không rác: Trong quá trình phân bổ và lập lịch định tuyến, không có rác bộ nhớ nào được tạo ra.
Hỗ trợ RestfulAPI: Thiết kế bộ định tuyến khuyến khích API Restful được phân lớp hợp lý.
Xử lý lỗi: Có thể thiết lập bộ xử lý lỗi để xử lý các ngoại lệ trong yêu cầu, bộ định tuyến sẽ bắt giữ và ghi lại, sau đó chuyển hướng đến trang lỗi.
Cách sử dụng cơ bản
Giống như springboot, một hàm liên kết với một URL và tương ứng với một bộ xử lý.
package main
import (
"fmt"
"github.com/julienschmidt/httprouter"
"log"
"net/http"
)
func Hello(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprintf(w, "<h1>Hello World!")
}
func main() {
router := httprouter.New()
router.GET("/hello", Hello)
log.Fatal(http.ListenAndServe(":8080", router))
}Sau đó sử dụng trình duyệt hoặc bất kỳ công cụ kiểm tra API nào nhập 127.0.0.1:8080, bạn sẽ thấy nội dung chính xác, chúng ta có thể thấy HttpRouter chỉ làm nhiệm vụ định tuyến, thực tế vẫn sử dụng thành phần mặc định net/http, gin cũng vậy, chỉ là việc đóng gói tương đối sâu hơn một chút.
Tham số có tên
package main
import (
"fmt"
"github.com/julienschmidt/httprouter"
"log"
"net/http"
)
func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
fmt.Fprintf(w, "<h1>Hello World!")
}
func main() {
router := httprouter.New()
router.GET("/hello:name", Hello)
log.Fatal(http.ListenAndServe(":8080", router))
}Lần này phía sau định tuyến thêm một :name, name là một tham số có tên, có thể truy cập slice tham số thông qua httprouter.Params, có thể lấy tham số thông qua chỉ mục hoặc ByName(name). Tương tự, bạn có thể sử dụng http.handler và http.handlerFunc như httprouter.handler, bản thân định tuyến đã triển khai interface của nó, ví dụ như ví dụ dưới đây.
func Hello(w http.ResponseWriter, r *http.Request) {
params := httprouter.ParamsFromContext(r.Context())
//params := r.Context().Value(httprouter.ParamsKey) cũng có thể
fmt.Fprintf(w, "hello, %s!\n", params.ByName("name"))
}Khi định tuyến liên kết với phương thức là /user/:user, các trường hợp khớp URL sau đây
/user/gordon khớp
/user/you khớp
/user/gordon/profile không khớp
/user/ không khớpBạn không thể đăng ký /user/new và /user/:user vào cùng một phương thức yêu cầu, mỗi phương thức yêu cầu nên độc lập với nhau.
Bắt tất cả tham số
Loại thứ hai là bắt tất cả tham số, đúng như tên gọi, chúng khớp với mọi thứ, do đó phải nằm ở cuối Pattern.
Pattern: /src/*filepath
/src/ khớp
/src/somefile.go khớp
/src/subdir/somefile.go khớpNguyên lý hoạt động của HttpRouter là xây dựng một số lượng lớn cây tiền tố, những người quan tâm có thể tìm hiểu: httprouter package - github.com/julienschmidt/httprouter - Go Packages.
OPTIONS & CORS
Một số người có thể muốn sửa đổi phản hồi tự động cho OPTIONS và thiết lập một số header phản hồi để phù hợp với yêu cầu preflight CORS, những yêu cầu này có thể được thực hiện bằng cách sử dụng bộ xử lý Router.GlobalOPTIONS.
router.GlobalOPTIONS = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Access-Control-Request-Method") != "" {
// Thiết lập header phản hồi CORS
header := w.Header()
header.Set("Access-Control-Allow-Methods", r.Header.Get("Allow"))
header.Set("Access-Control-Allow-Origin", "*")
}
// Phù hợp với mã trạng thái 204
w.WriteHeader(http.StatusNoContent)
})Bộ xử lý NOT FOUND
TIP
Có thể cần tắt Router.HandleMethodNotAllowed để tránh một số vấn đề.
router.NotFound = http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
// logic của bạn
})Xác thực cơ bản
package main
import (
"fmt"
"log"
"net/http"
"github.com/julienschmidt/httprouter"
)
func BasicAuth(h httprouter.Handle, requiredUser, requiredPassword string) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
// Lấy thông tin xác thực cơ bản
user, password, hasAuth := r.BasicAuth()
if hasAuth && user == requiredUser && password == requiredPassword {
// Ủy quyền yêu cầu cho bộ xử lý được cung cấp
h(w, r, ps)
} else {
// Yêu cầu xác thực
w.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
}
}
}
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, "Not protected!\n")
}
func Protected(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, "Protected!\n")
}
func main() {
user := "gordon"
pass := "secret!"
router := httprouter.New()
router.GET("/", Index)
router.GET("/protected/", BasicAuth(Protected, user, pass))
log.Fatal(http.ListenAndServe(":8080", router))
}