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)
    }))
}