我正在尝试编写简单的 http 服务器,它将为 API 请求提供服务。这是一个代码:
type Config struct {
ListenPort int `json:"listenPort"`
Requests []struct {
Request string `json:"request"`
ResponceFile string `json:"responceFile"`
} `json:"requests"`
}
...
func main() {
...
startServer(config)
}
func startServer(config Config) {
http.HandleFunc(apiPrefix+config.Requests[0].Request,
func(w http.ResponseWriter, r *http.Request) {
var dataStruct interface{}
err := loadJSON(config.Requests[0].ResponseFile, &dataStruct)
if err != nil {
w.Write([]byte("Oops! Something was wrong"))
}
data, _ := json.Marshal(dataStruct)
w.Header().Set("Content-Type", "application/json")
w.Write(data)
})
http.HandleFunc(apiPrefix+config.Requests[1].Request,
func(w http.ResponseWriter, r *http.Request) {
var dataStruct interface{}
err := loadJSON(config.Requests[1].ResponseFile, &dataStruct)
if err != nil {
w.Write([]byte("Oops! Something was wrong"))
}
data, _ := json.Marshal(dataStruct)
w.Header().Set("Content-Type", "application/json")
w.Write(data)
})
http.HandleFunc("/", http.NotFound)
port := ""
if config.ListenPort != 0 {
port = fmt.Sprintf(":%v", config.ListenPort)
} else {
port = ":8080"
}
fmt.Printf("Started @%v\n", port)
log.Fatal(http.ListenAndServe(port, nil))
}
func loadJSON(filePath string, retStruct interface{}) error {
fmt.Println(filePath)
fileJSON, err := ioutil.ReadFile(filePath)
json.Unmarshal(fileJSON, retStruct)
return err
}
这是配置,其中描述了应该通过特定请求返回的文件:
{
"listenPort": 8080,
"requests": [
{
"request": "switches/brocade",
"responseFile": "switches.json"
},
{
"request": "smth",
"responseFile": "smth.json"
}
]
}
所以问题是:为什么这段代码和上面的代码不一样?它只返回最后一个响应文件,在 config.json 中描述了来自这个文件的所有请求?或者什么是编写动态定义的处理程序的正确方法?
func startServer(config Config) {
for _, req := config.Requests {
http.HandleFunc(apiPrefix+req.Request,
func(w http.ResponseWriter, r *http.Request) {
var dataStruct interface{}
err := loadJSON(req.ResponseFile, &dataStruct)
if err != nil {
w.Write([]byte("Oops! Something was wrong"))
}
data, _ := json.Marshal(dataStruct)
w.Header().Set("Content-Type", "application/json")
w.Write(data)
})
}
http.HandleFunc("/", http.NotFound)
最佳答案
这是因为 Go 的范围循环重用声明的变量req
。
The iteration variables may be declared by the "range" clause using a form of short variable declaration (:=). In this case their types are set to the types of the respective iteration values and their scope is the block of the "for" statement; they are re-used in each iteration.
(强调我的)
这种行为以及您在 闭包 中捕获变量的事实是您所有的处理程序都引用最后一个变量的值的原因。
Function literals are closures: they may refer to variables defined in a surrounding function. Those variables are then shared between the surrounding function and the function literal, and they survive as long as they are accessible.
要解决这个问题,您可以从循环内的迭代变量创建一个新变量,并让闭包使用它。
关于api - 如何在golang中动态编写http.HandleFunc()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49204355/