Golang在路由之前修改HTTP请求参数,例如URL路径

Saw*_*lam 4 url routes http go server

在某些情况下,常见的做法是传递纯 URI 作为路径后缀而不是查询参数。这是来自互联网档案馆的 Wayback Machine 的示例。

https://web.archive.org/web/20150825082012/http://example.com/
Run Code Online (Sandbox Code Playgroud)

在此示例中,用户正在请求http://example.com/在 捕获的的副本2015-08-25 08:20:12。如果我们要在 Go 中实现类似的服务,我们可能会有一个如下的路由器:

http.HandleFunc("/web/", returnArchivedCopy)
Run Code Online (Sandbox Code Playgroud)

然后在returnArchivedCopy处理函数中,我们将拆分r.URL.Path(其中r是 Request 对象)以提取日期时间和目标 URL。然而,这种风格的 URL 方案存在一个问题:Go 的 net/http 包调用cleanPath路径部分上的函数来清理它。此清理过程执行各种清理任务,例如从路径中删除.和以及用单个斜杠替换多个斜杠。..后面的操作是有意义的,因为在 Unix 系统中//文件路径与/. 然而,这会导致上述用例中出现问题,http://example并且http:/example服务器在内部将带有清理路径的重定向响应返回给客户端。

我想知道,在这种情况下我有什么选择?有没有办法让 HTTP 不清理请求路径,同时仍然利用默认(或稍作修改)服务器、多路复用器和处理程序附带的所有默认行为?或者有没有办法在请求参数(本例中为路径)到达多路复用器的路由模式之前修改它。如果后者可能,我们可能会尝试执行 URL 编码之类的操作来避免重定向,然后在提取所需的位之前将 URL 解码回处理函数中。

我尝试过一些自定义处理程序和多路复用器,但我是 Go 新手,因此我不太确定在请求更改后如何将路由委托回默认处理程序。

One*_*One 5

您可以实现一个包装器多路复用器,它会回退到默认的多路复用器,这是一个非常简单的示例:

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)
    }))
}
Run Code Online (Sandbox Code Playgroud)

  • 感谢@OneOfOne 提供的详细示例。它做了我想要的。你太棒了! (2认同)