首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >嵌套ServeMux总是返回"301永久移动“

嵌套ServeMux总是返回"301永久移动“
EN

Stack Overflow用户
提问于 2020-02-21 19:15:21
回答 4查看 518关注 0票数 6

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

示例:

代码语言:javascript
复制
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的任何路由上。

我用的是围棋1.13和卷曲7.58。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2020-02-21 21:42:02

编辑:为了简化在火狐中的测试,我禁用了缓存。否则,我将不得不手动清除缓存,以获得准确的结果。不过,我在使用Chrome时似乎没有同样的问题。

记住我是新来的但这件事把我逼疯了..。我正经历着和你一样的行为(很明显)。

看来,Go/http对模式的格式化方式很挑剔。

我花了大约一个小时来处理这个问题,最后使用以下代码获得了一个工作示例:

代码语言:javascript
复制
// Working Code
package main

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

我尝试了尽可能多的不同配置(就/正斜杠而言),而上面的代码是我让它工作的唯一方法。

特别提到:

代码语言:javascript
复制
// Leading forward slash on /ping
api.HandleFunc("/ping", myHandlerFunc)

// The first /api/ is surrounded in forward slashes,
// the second /api only contains a leading forward slash
root.Handle("/api/", http.StripPrefix("/api", api))

将代码更改为这个会导致404.

代码语言:javascript
复制
// DOES NOT WORK!!
package main

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

我希望这在某种程度上有帮助!干杯

票数 5
EN

Stack Overflow用户

发布于 2020-02-21 22:24:46

前几天我只是在处理这个问题。我认为ServeMux需要有根的树(从/开始),或者它将路径解释为主机名。

模式命名固定的根路径,如"/favicon.ico",或根子树,如“/图像/”.模式可以选择以主机名开头,仅将匹配限制在该主机上。

我推测ping被解释为主机名,它在servemux的操作方式上造成了奇怪。

在人们编写的其他解决方案中,他们改变了/的位置,因此ping路径最终成为/ping

就我个人而言,我不喜欢在一个地方写/api/,在另一个地方写/api。在我的特殊情况下,我决定使用这样的方法:

代码语言:javascript
复制
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个值,这就不能很好地工作。

票数 1
EN

Stack Overflow用户

发布于 2021-03-11 09:32:42

我遇到了一个类似的问题,但只在尝试在嵌套路由器下定义根路径/的情况下。

为了处理它,我重写了自己的stripPefix()方法如下:

代码语言:javascript
复制
package main

import "net/http"

func main() {
    root := http.NewServeMux()
    api := http.NewServeMux()

    api.HandleFunc("/", myHandlerFunc)

    root.Handle("/api", stripPrefix("/api", api))

    http.ListenAndServe(":8080", root)
}

func myHandlerFunc(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("OK\n"))
}

// Modified version of http.StripPrefix()
func stripPrefix(prefix string, h http.Handler) http.Handler {
    if prefix == "" {
        return h
    }

    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if p := strings.TrimPrefix(r.URL.Path, prefix); len(p) < len(r.URL.Path) {
            r2 := new(http.Request)
            *r2 = *r
            r2.URL = new(url.URL)
            *r2.URL = *r.URL
            if len(p) == 0 {
                r2.URL.Path = "/"
            } else {
                r2.URL.Path = p
            }
            h.ServeHTTP(w, r2)
        } else {
            http.NotFound(w, r)
        }
    })
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60344955

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档