英文:
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
,服务器内部会返回一个重定向响应给客户端,其中包含经过清理的路径。
我想知道,在这种情况下我有哪些选择?有没有办法告诉HTTP在仍然利用默认(或稍作修改的)服务器、多路复用器和处理程序的所有默认行为的情况下,不对请求路径进行清理?或者有没有办法在请求参数(在这种情况下是路径)到达多路复用器的路由模式之前修改它们?如果后者是可能的,我们可以尝试执行类似URL编码的操作,以避免重定向,然后在处理函数中解码URL以提取所需的部分。
我已经尝试了一些自定义处理程序和多路复用器,但我对Go还不太熟悉,因此不太确定如何在更改请求后将路由委托给默认处理程序。
英文:
It's common practice in some cases to pass plain URIs as suffix of the path instead of a query parameter. Here is an example from Internet Archive's Wayback Machine.
https://web.archive.org/web/20150825082012/http://example.com/
In this example, user is requesting a copy of http://example.com/
as captured at 2015-08-25 08:20:12
. If we were to implement similar service in Go, we probably would have a router as follows:
http.HandleFunc("/web/", returnArchivedCopy)
Then in the returnArchivedCopy
handler function, we will split r.URL.Path
(where r
is the Request object) to extract the date-time and the target URL. However there is a problem in this style of URL scheme; Go's net/http package calls cleanPath
function on the path portion to sanitize it. This sanitization process does various cleanup tasks such as eeliminating .
and ..
from the path and replace multiple slashes with a single one. This later operation makes sense when because in Unix systems //
in the file path are same as /
. However this causes an issue in the above described use case as http://example
becomes http:/example
and the server internally returns a redirect response to the client with the sanitized path.
I am wondering, what are my options in this case? Is there a way to ask HTTP not to sanitize the request path while still utilizing all the default behavior that is shipped with the default (or slightly modified) server, multiplexer, and handler? Or is there a way to modify the request parameters (path in this case) before it hits the multiplexer's routing patterns. If the later is possible, we might try to perform something like URL encoding to avoid the redirect and later decode the URL back in the handler function before extracting desired bits.
I have experimented with some custom handlers and multiplexers, but I am new to Go, hence I was not quite sure how to delegate the routing back to the default handlers after making changes in the request.
答案1
得分: 5
你可以实现一个包装器mux,它会回退到默认的mux,这里有一个非常简单的示例:
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)
}))
}
希望对你有帮助!
英文:
You can implement a wrapper mux, that falls back to the default one, here's a very simple example:
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)
}))
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论