动态实例化HandleFunc

huangapple go评论79阅读模式
英文:

Dynamically instantiating HandleFunc

问题

我一直在努力理解如何以动态方式实现HandleFunc()

我想将这个yaml文件转换为Go语言中的本地HTTP Web服务器。

# Example .mock.yaml config
Endpoints:
  - Resource: /city/1
    Method: GET
    Response: '{ "Id": 1, "Name": "Albuquerque", "Population": 559.374, "State": "New Mexico" }'
    StatusCode: 200

  - Resource: /city
    Method: POST
    Response: '{ "Name": "Albuquerque", "Population": 559.374, "State": "New Mexico" }'
    StatusCode: 200

  - Resource: /city/1
    Method: PUT
    Response: '{ "Population": 601.255 }'
    StatusCode: 204

  - Resource: /city/1
    Method: DELETE
    StatusCode: 204

现在我成功实现了以下代码:

package utils

import (
	"io"
	"net/http"

	"github.com/gorilla/mux"

	"github.com/bschaatsbergen/mock/model"
)

func StartServer(conf model.Config, port string) {
	r := mux.NewRouter()

	for _, endpoint := range conf.Endpoints {
		r.HandleFunc(endpoint.Resource, func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(endpoint.StatusCode)

			io.WriteString(w, endpoint.Response)
		}).Methods(endpoint.Method)
	}

	address := ":" + port

	http.ListenAndServe(address, r)
}

但是这样做不够好,因为它会覆盖先前创建的路由('/city/1'的GET、DELETE和POST方法冲突)。

如果有人能帮我解决如何将yaml配置动态转换为本地Web服务器,我将不胜感激!

英文:

I've been trying to wrap my head around implementing HandleFunc() in a dynamic way.

This yaml file I want to turn into a local http web server in Go.

# Example .mock.yaml config
Endpoints:
  - Resource: /city/1
    Method: GET
    Response: '{ Id": 1, "Name": "Albuquerque", "Population": 559.374, "State": "New Mexico" }'
    StatusCode: 200

  - Resource: /city
    Method: POST
    Response: '{ "Name": "Albuquerque", "Population": 559.374, "State": "New Mexico" }'
    statusCode: 200

  - Resource: /city/1
    Method: PUT
    Response: '{ "Population": 601.255 }'
    StatusCode: 204

  - Resource: /city/1
    Method: DELETE
    StatusCode: 204

Now I managed to implement something as following:

package utils

import (
	"io"
	"net/http"

	"github.com/gorilla/mux"

	"github.com/bschaatsbergen/mock/model"
)

func StartServer(conf model.Config, port string) {
	r := mux.NewRouter()

	for _, endpoint := range conf.Endpoints {
		r.HandleFunc(endpoint.Resource, func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(endpoint.StatusCOde)

			io.WriteString(w, endpoint.Response)
		}).Methods(endpoint.Method)
	}

	address := ":" + port

	http.ListenAndServe(address, r)
}

^ https://play.golang.org/p/YoTTUKnQL_5

But this doesn't cut it as it overwrites an earlier created route ('/city/1' GET, DELETE and POST are conflicting).

If anyone could give me a hand on how to dynamically translate the yaml config into a local web server, it would be appreciated!

答案1

得分: 2

我引用了@mkopriva的话,谢谢!

> 我相当确定你的问题与这里的问题相同:
> stackoverflow.com/questions/69595865/…。也就是说,你所有的匿名处理程序闭包都捕获了同一个变量,即迭代变量,在循环结束时,它将保存Endpoints切片的最后一个元素。正确吗?这个问题可以关闭为重复吗?

工作的代码片段:

func StartServer(conf model.Config, port string) {
	r := mux.NewRouter()

	for _, endpoint := range conf.Endpoints {
		route := endpoint
		r.HandleFunc(route.Resource, func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(route.Statuscode)
			io.WriteString(w, route.Response)
		}).Methods(route.Method)
	}

	address := ":" + port

	log.Fatal(http.ListenAndServe(address, r))
}
英文:

I quote from @mkopriva, thanks!

> I'm fairly certain your problem is the same as the one here:
> stackoverflow.com/questions/69595865/…. i.e. All of your anon handler
> closures capture one and the same variable, the iteration variable,
> which, at the end of the loop, will hold the last element of the
> Endpoints slice. Correct? Can the question be closed as duplicate?

Working piece of code:

func StartServer(conf model.Config, port string) {
	r := mux.NewRouter()

	for _, endpoint := range conf.Endpoints {
		route := endpoint
		r.HandleFunc(route.Resource, func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(route.Statuscode)
			io.WriteString(w, route.Response)
		}).Methods(route.Method)
	}

	address := ":" + port

	log.Fatal(http.ListenAndServe(address, r))
}

huangapple
  • 本文由 发表于 2021年10月19日 20:12:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/69630603.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定