The Coder The Coder - 3 years ago 254
HTTP Question

Golang "301 Moved Permanently" if request path contains additional slash

I have been using golang's default

for http route handling.

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

Assume this server is accessible via

Very few of my client's requests were of path
(note the extra slash) which is redirected as
301 Moved Permanently
. Exploring inside golang's http
ServeMux.Handler(r *Request)
function, seems it's intended.

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

I've looked into other similar issue.


Above qn has problem with redundant
in register pattern itself, but my use case is not with register pattern (in some nested path which is irrelevent to register pattern)

Problem is, since my client's requests are
, browsers handle 301 with new
request with exact query params and POST body. But change in the HTTP method causes the request to fail.

I have already instructed client to fix the redundant
in url, but the fix might take few (?) weeks to be deployed in all client locations.

Also these redundant
are handled fine in
Apache Tomcat
, but fails only in golang server. So is this the intended behaviour in my use case (redundant
in nested path) with golang or possible bug?

I am thinking of way to override the
func of
, but it won't be useful since
calls are made internally. Looking to disable this 301 behaviour, help would be appreciated.

Relevant links


Answer Source

The clean and redirect is intended behavior.

Wrap the mux with a handler that removes the double slashes:

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)

Use it like this:

httpMux := http.NewServeMux()
httpMux.HandleFunc("/", wrap(payloadHandler))
http.ListenAndServe(addr, &fixSlash{httpMux})
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download