猿问

嵌套的 ServeMux 总是返回“301 Moved Permanently”

当使用嵌套http.ServeMux来定义我的服务器的端点时,我遇到了这个问题:处理程序总是会以“301 永久移动”响应任何请求,即使 URL 路径应该匹配。


例子:


package main


import "net/http"


func main() {

    api := http.NewServeMux()

    api.HandleFunc("ping", func(w http.ResponseWriter, r *http.Request) {

        w.Write([]byte("pong\n"))

    })


    root := http.NewServeMux()

    root.Handle("/api/", http.StripPrefix("/api/", api))

    http.ListenAndServe(":8080", root)

}

尝试访问/api/ping时,服务器重定向到/ping(当然返回 404)。同样的事情发生在任何路由下/api/-/api/foo重定向到/foo.


我正在使用 Go 1.13 和 curl 7.58。


MMTTMM
浏览 219回答 3
3回答

拉丁的传说

为了让 Firefox 中的测试更容易,我禁用了缓存。否则我将不得不手动清除缓存以获得准确的结果。不过,在使用 Chrome 时,我似乎没有遇到同样的问题。请记住,我是 Go 新手,但这个问题让我发疯了......我遇到了与你完全相同的行为(显然)......Go/http 似乎对模式的格式化方式很挑剔..我搞砸了大约一个小时,终于能够使用以下代码获得一个工作示例:// Working Codepackage mainimport "net/http"func main() {    root := http.NewServeMux()    api := http.NewServeMux()    api.HandleFunc("/ping", myHandlerFunc)    root.Handle("/api/", http.StripPrefix("/api", api))    http.ListenAndServe(":8080", root)}func myHandlerFunc(w http.ResponseWriter, r *http.Request) {    w.Write([]byte("pong\n"))}我尝试了尽可能多的不同配置(/就正斜杠而言),上面的代码是我让它工作的唯一方法..具体指:// Leading forward slash on /pingapi.HandleFunc("/ping", myHandlerFunc)// The first /api/ is surrounded in forward slashes,// the second /api only contains a leading forward slashroot.Handle("/api/", http.StripPrefix("/api", api))将代码更改为此会导致 404...// DOES NOT WORK!!package mainimport "net/http"func main() {    root := http.NewServeMux()    api := http.NewServeMux()    api.HandleFunc("/ping", myHandlerFunc)    root.Handle("/api", http.StripPrefix("/api", api))    http.ListenAndServe(":8080", root)}func myHandlerFunc(w http.ResponseWriter, r *http.Request) {    w.Write([]byte("pong\n"))}我希望这在某种程度上有所帮助!干杯

慕桂英4014372

前几天我正在处理这个问题。我认为ServeMux期望有根树(以 开头/),或者它将路径解释为主机名。模式名称固定,有根路径,如“/favicon.ico”,或有根子树,如“/images/”.... 模式可以选择以主机名开头,将匹配限制为仅该主机上的 URL。我推测这ping被解释为主机名,这会导致 servermux 的运行方式变得怪异。在人们编写的其他解决方案中,他们围绕 的位置进行更改,/以使ping路线最终为/ping。就个人而言,我不喜欢我必须/api/在一个地方和/api另一个地方写作。在我的特殊情况下,我决定使用类似的东西:root.Handle(createAPIEndpoints("/api/"))...func createAPIEndpoints(base string) (string, *http.ServeMux) {    mux := http.NewServeMux()    mux.HandleFunc(base+"ping", func(...){...})    mux.HandleFunc(base+"another", func(...){...})    // another buried servemux    mux.Handle(createMoreEndpoints(base+"more/"))    return base, mux}但是,如果您想用处理程序包装处理程序(例如使用StripPrefix或其他类型的中间件,由于返回 2 个值,这不能很好地工作。

ITMISS

我遇到了类似的问题,但仅在您尝试/在嵌套路由器下定义根路径的情况下。为了处理它,我重写了我自己的 stripPefix() 方法,如下所示:package mainimport "net/http"func main() {&nbsp; &nbsp; root := http.NewServeMux()&nbsp; &nbsp; api := http.NewServeMux()&nbsp; &nbsp; api.HandleFunc("/", myHandlerFunc)&nbsp; &nbsp; root.Handle("/api", stripPrefix("/api", api))&nbsp; &nbsp; http.ListenAndServe(":8080", root)}func myHandlerFunc(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; w.Write([]byte("OK\n"))}// Modified version of http.StripPrefix()func stripPrefix(prefix string, h http.Handler) http.Handler {&nbsp; &nbsp; if prefix == "" {&nbsp; &nbsp; &nbsp; &nbsp; return h&nbsp; &nbsp; }&nbsp; &nbsp; return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; &nbsp; &nbsp; if p := strings.TrimPrefix(r.URL.Path, prefix); len(p) < len(r.URL.Path) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; r2 := new(http.Request)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *r2 = *r&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; r2.URL = new(url.URL)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *r2.URL = *r.URL&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if len(p) == 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; r2.URL.Path = "/"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; r2.URL.Path = p&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; h.ServeHTTP(w, r2)&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; http.NotFound(w, r)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; })}
随时随地看视频慕课网APP

相关分类

Go
我要回答