在某些情况下,通常的做法是将普通URI作为路径的后缀而不是查询参数传递。以下是Internet Archive的Wayback Machine的一个示例。
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。但是这种URL方案存在问题; Go的net / http包调用路径部分上的cleanPath
函数来清理它。此清理过程执行各种清理任务,例如从路径中删除.
和..
并使用单个斜杠替换多个斜杠。后来的操作是有意义的,因为在Unix系统中,文件路径中的//
与/
相同。但是,这导致上述用例中的问题,因为http://example
变为http:/example
,并且服务器在内部向具有已清理路径的客户端返回重定向响应。
我想知道,在这种情况下我有什么选择?有没有办法让HTTP不要清理请求路径,同时仍然使用默认(或略微修改)的服务器,多路复用器和处理程序附带的所有默认行为?或者有没有办法在它到达多路复用器的路由模式之前修改请求参数(在这种情况下为路径)。如果后者是可能的,我们可能会尝试执行类似URL编码的操作以避免重定向,然后在处理程序函数中将URL解码回来,然后再提取所需的位。
我已经尝试过一些自定义处理程序和多路复用器,但我是Go的新手,因此我不太确定在对请求进行更改后如何将路由委托给默认处理程序。
答案 0 :(得分: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)
}))
}