2015-08-27 268 views
1

在某些情況下,通常會將普通URI作爲路徑的後綴而不是查詢參數傳遞。這是來自Internet Archive的Wayback Machine的一個例子。Golang修改路由前的URL路徑等HTTP請求參數

https://web.archive.org/web/20150825082012/http://example.com/ 

在該示例中,用戶正在請求的http://example.com/副本作爲在2015-08-25 08:20:12捕獲。如果我們要實現在Go類似的服務,我們可能有一個路由器如下:

http.HandleFunc("/web/", returnArchivedCopy) 

然後在returnArchivedCopy處理函數,我們將分裂r.URL.Path(其中r是Request對象)中提取的日期 - 時間和目標網址。但是這種URL方案存在問題; Go的net/http包在路徑部分調用cleanPath函數來清理它。此消毒過程執行各種清理任務,例如從路徑中消除...,並用單個替換多個斜線。這後面的操作是合理的,因爲在Unix系統中文件路徑中的///相同。但是,這導致上述用例中的問題,因爲http://example變爲http:/example,並且服務器在內部將重定向響應返回給具有清理路徑的客戶端。

我想知道,在這種情況下我的選擇是什麼?有沒有辦法要求HTTP不要清理請求路徑,同時仍然使用默認(或稍微修改)的服務器,多路複用器和處理程序附帶的所有默認行爲?或者有沒有辦法在碰到多路複用器的路由模式之前修改請求參數(在這種情況下是路徑)。如果後者可行,我們可能會嘗試執行類似URL編碼的操作,以避免重定向,並稍後在處理函數中將URL解碼回來,然後提取所需的位。

我已經試驗了一些自定義的處理程序和多路複用器,但我的新去的,所以我不太確定如何委派使得在請求更改後的路由返回到默認的處理程序。

回答

1

您可以實現一個包裝複用器,即回落到默認的,這裏有一個很簡單的例子:

func main() { 
    http.HandleFunc("/blah", func(w http.ResponseWriter, req *http.Request) { 
     w.Write([]byte("w00t")) 
    }) 
    http.ListenAndServe(":9090", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 
     p := strings.SplitN(req.URL.RequestURI()[1:] /*trim the first slash*/, "/", 3) 
     if len(p) != 3 || p[0] != "web" { 
      http.DefaultServeMux.ServeHTTP(w, req) 
      return 
     } 

     t, err := time.Parse("20060102150405", p[1]) 
     if err != nil { 
      http.Error(w, "invalid time", 400) 
      return 
     } 
     url := p[2] 
     fmt.Fprintf(w, "requested url %v @ %v", url, t) 
    })) 
} 
+1

感謝@OneOfOne了詳盡的例子。它做了我想要的。你太棒了! –