HttpRouter
저장소 주소: julienschmidt/httprouter: A high performance HTTP request router that scales well (github.com)
Gin 의 라우팅 컴포넌트는 HttpRouter 를 사용하며 이 역시 경량이고 고성능의 라우팅 컴포넌트입니다. 전체 컴포넌트는 단 세 개의 .go 파일로 구성되어 있으며 코드가 매우 간결합니다. 주요 특징은 다음과 같습니다.
일대일 매칭: 하나의 요청은 0 개 또는 하나의 라우팅에만 매칭될 수 있으며 SEO 최적화에 유리합니다.
경로 자동 보정: 원하는 URL 스타일을 자유롭게 선택할 수 있으며 슬래시가 많거나 적어도 자동으로 리디렉션됩니다. 대소문자 오류가 있는 경우에도 대소문자를 무시하고 올바르게 리디렉션됩니다.
라우팅 파라미터 자동 파싱: 경로 세그먼트에 이름을 지정하면 라우터가 동적 값을 전달합니다. 라우터 설계로 인해 경로 파라미터 파싱의 오버헤드가 매우 낮습니다.
제로 가비지: 라우팅 할당 및 스케줄링 과정에서 메모리 가비지가 생성되지 않습니다.
RestfulAPI 지원: 라우터 설계는 합리적인 계층적 Restful API 를 장려합니다.
오류 처리: 요청의 예외를 처리할 오류 핸들러를 설정할 수 있으며 라우터가 이를 캡처하고 기록한 후 오류 페이지로 리디렉션합니다.
기본 사용법
springboot 와 마찬가지로 하나의 함수가 하나의 URL 에 바인딩되고 하나의 처리기에 해당합니다.
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))
}이후 브라우저나 인터페이스 테스트 도구를 사용하여 127.0.0.1:8080 에 접속하면 올바른 콘텐츠를 볼 수 있습니다. HttpRouter 는 라우팅만 수행했을 뿐이며 실제로는 여전히 net/http 기본 컴포넌트를 사용합니다. gin 도 마찬가지이며 다만 캡슐화가 더 깊을 뿐입니다.
명명된 파라미터
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))
}이번에는 라우팅 뒤에 :name 이 추가되었으며 name 은 명명된 파라미터입니다. httprouter.Params 를 통해 파라미터 슬라이스에 접근할 수 있으며 인덱스 또는 ByName(name) 을 통해 파라미터를 가져올 수 있습니다. 마찬가지로 http.handler 와 http.handlerFunc 를 httprouter.handler 로 사용할 수 있으며 라우팅 자체가 인터페이스를 구현합니다. 아래 예제를 보십시오.
func Hello(w http.ResponseWriter, r *http.Request) {
params := httprouter.ParamsFromContext(r.Context())
//params := r.Context().Value(httprouter.ParamsKey) 도 가능
fmt.Fprintf(w, "hello, %s!\n", params.ByName("name"))
}메서드가 바인딩된 라우팅이 /user/:user 일 때 다음几种 URL 의 매칭 상황입니다.
/user/gordon match
/user/you match
/user/gordon/profile no match
/user/ no match/user/new 과 /user/:user 를 동일한 요청 메서드에 등록할 수는 없으며 각 요청 메서드는 서로 독립적이어야 합니다.
전체 파라미터 캡처
두 번째 타입은 전체 파라미터를 캡처하는 것으로 말 그대로 모든 것을 매칭하므로 Pattern 의 끝에 위치해야 합니다.
Pattern: /src/*filepath
/src/ match
/src/somefile.go match
/src/subdir/somefile.go matchHttpRouter 의 작동 원리는 대량의 프리픽스 트리를 구축하는 것이며 관심 있는 분은 참고하시기 바랍니다: httprouter package - github.com/julienschmidt/httprouter - Go Packages.
OPTIONS & CORS
일부 사람들은 OPTIONS 에 대한 자동 응답을 수정하고 CORS 프리플라이트 요청에适配하기 위해 일부 응답 헤더를 설정하기를 원할 수 있습니다. 이러한 요구사항은 Router.GlobalOPTIONS 핸들러를 통해 구현할 수 있습니다.
router.GlobalOPTIONS = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Access-Control-Request-Method") != "" {
// CORS 응답 헤더 설정
header := w.Header()
header.Set("Access-Control-Allow-Methods", r.Header.Get("Allow"))
header.Set("Access-Control-Allow-Origin", "*")
}
// 상태 코드 204 에适配
w.WriteHeader(http.StatusNoContent)
})NOT FOUND 핸들러
TIP
일부 문제를 피하기 위해 Router.HandleMethodNotAllowed 를 끄는 것이 필요할 수 있습니다.
router.NotFound = http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
// 로직 작성
})기본 인증
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) {
// 기본 인증 자격 증명 가져오기
user, password, hasAuth := r.BasicAuth()
if hasAuth && user == requiredUser && password == requiredPassword {
// 요청을 주어진 처리기에 위임
h(w, r, ps)
} else {
// 그렇지 않으면 인증 요청
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))
}