Golang “301 永久移动”如果请求路径包含额外的斜杠
Golang "301 Moved Permanently" if request path contains additional slash
我一直在使用 golang 的默认 http.ServeMux
进行 http 路由处理。
wrap := func(h func(t *MyStruct, w http.ResponseWriter, r *http.Request)) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
h(t, w, r)
}
}
// Register handlers with default mux
httpMux := http.NewServeMux()
httpMux.HandleFunc("/", wrap(payloadHandler))
假设可以通过 http://example.com/
访问此服务器
我客户的请求中很少有路径 http://example.com/api//module
(注意额外的斜线)被重定向为 301 Moved Permanently
。深入golang的httpServeMux.Handler(r *Request)
函数,似乎是有意的。
path := cleanPath(r.URL.Path)
// if there is any change between actual and cleaned path, the request is 301 ed
if path != r.URL.Path {
_, pattern = mux.handler(host, path)
url := *r.URL
url.Path = path
return RedirectHandler(url.String(), StatusMovedPermanently), pattern
}
我调查了其他类似问题。
上面的 qn 在寄存器模式本身中存在冗余 /
的问题,但我的用例不是寄存器模式(在一些与寄存器模式无关的嵌套路径中)
问题是,由于我的客户的请求是 POST
,浏览器使用具有精确查询参数和 POST 正文的新 GET
请求处理 301。但是 HTTP 方法的更改导致请求失败。
我已经指示客户修复 url 中的冗余 /
,但修复可能需要几周(?)周才能部署到所有客户位置。
此外,这些冗余 /
在 Apache Tomcat
中处理得很好,但仅在 golang 服务器中失败。那么这是我用例中的预期行为(嵌套路径中的冗余 /
)与 golang 或可能的错误吗?
我正在考虑覆盖 ServeMux
的 Handler
函数的方法,但它不会有用,因为 Handler
调用是在内部进行的。希望禁用此 301 行为,将不胜感激。
相关链接
清除和重定向是预期的行为。
用删除双斜杠的处理程序包装 mux:
type slashFix struct {
mux http.Handler
}
func (h *slashFix) ServeHTTP(w http.ResponseWriter, r *http.Request) {
r.URL.Path = strings.Replace(r.URL.Path, "//", "/", -1)
h.mux.ServeHTTP(w, r)
}
这样使用:
httpMux := http.NewServeMux()
httpMux.HandleFunc("/", wrap(payloadHandler))
http.ListenAndServe(addr, &slashFix{httpMux})
接受的答案解决了问题
另一种方法是使用 Gorilla mux and setting SkipClean(true)
. But be sure to know about the side effects in its doc
SkipClean defines the path cleaning behaviour for new routes. The initial value is false. Users should be careful about which routes are not cleaned. When true, if the route path is "/path//to", it will remain with the double slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/
When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will become /fetch/http/xkcd.com/534
func (r *Router) SkipClean(value bool) *Router {
r.skipClean = value
return r
}
我一直在使用 golang 的默认 http.ServeMux
进行 http 路由处理。
wrap := func(h func(t *MyStruct, w http.ResponseWriter, r *http.Request)) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
h(t, w, r)
}
}
// Register handlers with default mux
httpMux := http.NewServeMux()
httpMux.HandleFunc("/", wrap(payloadHandler))
假设可以通过 http://example.com/
我客户的请求中很少有路径 http://example.com/api//module
(注意额外的斜线)被重定向为 301 Moved Permanently
。深入golang的httpServeMux.Handler(r *Request)
函数,似乎是有意的。
path := cleanPath(r.URL.Path)
// if there is any change between actual and cleaned path, the request is 301 ed
if path != r.URL.Path {
_, pattern = mux.handler(host, path)
url := *r.URL
url.Path = path
return RedirectHandler(url.String(), StatusMovedPermanently), pattern
}
我调查了其他类似问题。
上面的 qn 在寄存器模式本身中存在冗余 /
的问题,但我的用例不是寄存器模式(在一些与寄存器模式无关的嵌套路径中)
问题是,由于我的客户的请求是 POST
,浏览器使用具有精确查询参数和 POST 正文的新 GET
请求处理 301。但是 HTTP 方法的更改导致请求失败。
我已经指示客户修复 url 中的冗余 /
,但修复可能需要几周(?)周才能部署到所有客户位置。
此外,这些冗余 /
在 Apache Tomcat
中处理得很好,但仅在 golang 服务器中失败。那么这是我用例中的预期行为(嵌套路径中的冗余 /
)与 golang 或可能的错误吗?
我正在考虑覆盖 ServeMux
的 Handler
函数的方法,但它不会有用,因为 Handler
调用是在内部进行的。希望禁用此 301 行为,将不胜感激。
相关链接
清除和重定向是预期的行为。
用删除双斜杠的处理程序包装 mux:
type slashFix struct {
mux http.Handler
}
func (h *slashFix) ServeHTTP(w http.ResponseWriter, r *http.Request) {
r.URL.Path = strings.Replace(r.URL.Path, "//", "/", -1)
h.mux.ServeHTTP(w, r)
}
这样使用:
httpMux := http.NewServeMux()
httpMux.HandleFunc("/", wrap(payloadHandler))
http.ListenAndServe(addr, &slashFix{httpMux})
接受的答案解决了问题
另一种方法是使用 Gorilla mux and setting SkipClean(true)
. But be sure to know about the side effects in its doc
SkipClean defines the path cleaning behaviour for new routes. The initial value is false. Users should be careful about which routes are not cleaned. When true, if the route path is "/path//to", it will remain with the double slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/
When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will become /fetch/http/xkcd.com/534
func (r *Router) SkipClean(value bool) *Router {
r.skipClean = value
return r
}