Golang在路由前修改URL路径等HTTP请求参数
Golang Modify HTTP Request Parameters Such As URL Path Before Routing
在某些情况下,通常的做法是将纯 URI 作为路径后缀而不是查询参数传递。这是 Internet Archive 的 Wayback Machine 中的示例。
https://web.archive.org/web/20150825082012/http://example.com/
在此示例中,用户正在请求在 2015-08-25 08:20:12
捕获的 http://example.com/
的副本。如果我们要在 Go 中实现类似的服务,我们可能会有一个如下所示的路由器:
http.HandleFunc("/web/", returnArchivedCopy)
然后在 returnArchivedCopy
处理函数中,我们将拆分 r.URL.Path
(其中 r
是 Request 对象)以提取日期时间和目标 URL .然而,这种URL方案的风格存在一个问题; Go 的 net/http 包在路径部分调用 cleanPath
函数来清理它。此清理过程执行各种清理任务,例如从路径中删除 .
和 ..
并将多个斜杠替换为单个斜杠。这后面的操作是有意义的,因为在 Unix 系统中 //
在文件路径中与 /
相同。然而,这会在上述用例中导致问题,因为 http://example
变为 http:/example
并且服务器在内部 returns 使用经过清理的路径对客户端进行重定向响应。
我想知道,在这种情况下我有什么选择?有没有办法要求 HTTP 在仍然利用默认(或稍作修改的)服务器、多路复用器和处理程序附带的所有默认行为的同时不清理请求路径?或者有没有办法在它达到多路复用器的路由模式之前修改请求参数(在这种情况下为路径)。如果后者可行,我们可能会尝试执行类似 URL 编码的操作来避免重定向,然后在提取所需位之前在处理程序函数中解码 URL 。
我尝试过一些自定义处理程序和多路复用器,但我是 Go 的新手,因此我不太确定如何在更改请求后将路由委托回默认处理程序。
您可以实现一个包装器多路复用器,回退到默认的,这是一个非常简单的例子:
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)
}))
}
在某些情况下,通常的做法是将纯 URI 作为路径后缀而不是查询参数传递。这是 Internet Archive 的 Wayback Machine 中的示例。
https://web.archive.org/web/20150825082012/http://example.com/
在此示例中,用户正在请求在 2015-08-25 08:20:12
捕获的 http://example.com/
的副本。如果我们要在 Go 中实现类似的服务,我们可能会有一个如下所示的路由器:
http.HandleFunc("/web/", returnArchivedCopy)
然后在 returnArchivedCopy
处理函数中,我们将拆分 r.URL.Path
(其中 r
是 Request 对象)以提取日期时间和目标 URL .然而,这种URL方案的风格存在一个问题; Go 的 net/http 包在路径部分调用 cleanPath
函数来清理它。此清理过程执行各种清理任务,例如从路径中删除 .
和 ..
并将多个斜杠替换为单个斜杠。这后面的操作是有意义的,因为在 Unix 系统中 //
在文件路径中与 /
相同。然而,这会在上述用例中导致问题,因为 http://example
变为 http:/example
并且服务器在内部 returns 使用经过清理的路径对客户端进行重定向响应。
我想知道,在这种情况下我有什么选择?有没有办法要求 HTTP 在仍然利用默认(或稍作修改的)服务器、多路复用器和处理程序附带的所有默认行为的同时不清理请求路径?或者有没有办法在它达到多路复用器的路由模式之前修改请求参数(在这种情况下为路径)。如果后者可行,我们可能会尝试执行类似 URL 编码的操作来避免重定向,然后在提取所需位之前在处理程序函数中解码 URL 。
我尝试过一些自定义处理程序和多路复用器,但我是 Go 的新手,因此我不太确定如何在更改请求后将路由委托回默认处理程序。
您可以实现一个包装器多路复用器,回退到默认的,这是一个非常简单的例子:
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)
}))
}