難免會有無聊的使用者這樣玩網址
/owner//////proj1//pro2/blog////
如果對這種request也想正常服務,可以設置gin.Engine的RemoveExtraSlash為true,gin會在內部呼叫cleanPath這個function
但還有更重要的問題,我們的路由定義/:owner/*project
,這代表就算是/owner/也會rout到GetProject,而cleanPath雖然在處理的過程中會把最後的"/"刪掉,但最後要輸出時會再加"/"回去...
這問題不能在middleware處理,在進入middleware時gin就已經決定好路由了,所以我們要在ServeHTTP處理這問題
因為cleanPath沒有export,所以我直接把它複製出來用了,嫌麻煩就直接改源碼吧,只要把"/"加回去的那段程式碼刪掉就好了
更改host_switch.go(礙於篇幅,我把大部分的註解刪掉了,只留下要我修改的註解,想搞懂可以去看源碼)
// Implement the ServeHTTP method on our new type
func (hs HostSwitch) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Check if a http.Handler is registered for the given host.
// If yes, use it to handle the request.
if handler := hs[r.Host]; handler != nil {
// clean path
path := cleanPath(r.URL.Path)
// update to request
r2 := new(http.Request)
*r2 = *r
r2.URL = new(url.URL)
*r2.URL = *r.URL
r2.URL.Path = path
handler.ServeHTTP(w, r2)
} else {
// Handle host names for which no handler is registered
http.Error(w, "Forbidden", 403) // Or Redirect?
}
}
func cleanPath(p string) string {
const stackBufSize = 128
if p == "" {
return "/"
}
buf := make([]byte, 0, stackBufSize)
n := len(p)
r := 1
w := 1
if p[0] != '/' {
r = 0
if n+1 > stackBufSize {
buf = make([]byte, n+1)
} else {
buf = buf[:n+1]
}
buf[0] = '/'
}
// trailing := n > 1 && p[n-1] == '/' 這裡
for r < n {
switch {
case p[r] == '/':
r++
case p[r] == '.' && r+1 == n:
// trailing = true 這裡
r++
case p[r] == '.' && p[r+1] == '/':
r += 2
case p[r] == '.' && p[r+1] == '.' && (r+2 == n || p[r+2] == '/'):
r += 3
if w > 1 {
w--
if len(buf) == 0 {
for w > 1 && p[w] != '/' {
w--
}
} else {
for w > 1 && buf[w] != '/' {
w--
}
}
}
default:
if w > 1 {
bufApp(&buf, p, w, '/')
w++
}
for r < n && p[r] != '/' {
bufApp(&buf, p, w, p[r])
w++
r++
}
}
}
/*
// Re-append trailing slash 這裡
if trailing && w > 1 {
bufApp(&buf, p, w, '/')
w++
}
*/
if len(buf) == 0 {
return p[:w]
}
return string(buf[:w])
}
func bufApp(buf *[]byte, s string, w int, c byte) {
b := *buf
if len(b) == 0 {
if s[w] == c {
return
}
if l := len(s); l > cap(b) {
*buf = make([]byte, len(s))
} else {
*buf = (*buf)[:l]
}
b = *buf
copy(b, s[:w])
}
b[w] = c
}
解釋:
// Except for reading the body, handlers should not modify the
// provided Request.
測測看結果
curl GET "http://127.0.0.1:8000//wew6////1/2/3/////4/5/6/7/8/////////"
{"blog":"8","owner":"wew6","project":["1","2","3","4","5","6","7"]}
api的雛型架構就這樣了,明天開始來寫通用的middleware
今天工作環境沒變動