Request reroute in Go, map HandleFuncs

56 views Asked by At

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!

2

There are 2 answers

5
leaf bebop On BEST ANSWER

The problem is that all the handle functions are accessing the same req and path 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 before http.HandleFunc(...).

It seems weird. What it does is to declare new req and path in the scope of loop, which is new every iteration, so every closure binds to different value.

0
stef On

Another solution would be the one used here (which I thanks to the answer now understand): https://github.com/golang/blog/blob/master/rewrite.go:

path := fileRoutes[req] before http.HandleFunc