I want to map path names to files that live at a different location. But my code serves /path/c.txt
when I visit /a
, instead of /path/a.txt
. What am I doing wrong?
package main
import (
"fmt"
"net/http"
)
func main() {
fileRoutes := map[string]string {
"/a": "/path/a.txt",
"/b": "/path/b.txt",
"/c": "/path/c.txt",
}
for req, path := range fileRoutes {
http.HandleFunc(req, func(w http.ResponseWriter, r *http.Request) {
fmt.Printf("actual request: %v\n", r.URL.Path)
fmt.Printf("registered request: %v\n", req)
r.URL.Path = path
fmt.Println(req)
fmt.Println(path)
// serveFile(w, r)
})
}
http.ListenAndServe(":8004", nil)
}
This sample code produces:
actual request: /a
registered request: /c
/c
/path/c.txt
Thank you!
The problem is that all the handle functions are accessing the same
req
andpath
that is set to the last variable of the loop after the loop, which are/c
and/path/c.txt
.To fix the problem, add
req,path := req,path
beforehttp.HandleFunc(...)
.It seems weird. What it does is to declare new
req
andpath
in the scope of loop, which is new every iteration, so every closure binds to different value.