如何在单个入口点中自定义来自两个处理程序的响应数据?

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

How to customize a response data from two handlers in single entrypoint go?

问题

我在我的应用程序中使用了echo框架,并且在单个入口点上使用两个处理程序构建响应时遇到了问题。

以下是示例代码:

type RespObject struct {
	Message string `json:"message"`
}

func main() {
	e := echo.New()
	e.GET("/hello", handler, middle)

	e.Logger.Fatal(e.Start(":3000"))
}

func handler(c echo.Context) error {
	return c.JSON(http.StatusOK, RespObject{
		Message: "Hello",
	})
}

func middle(next echo.HandlerFunc) echo.HandlerFunc {
	return func(c echo.Context) error {
		c.JSON(http.StatusOK, RespObject{
			Message: "World",
		})
		return next(c)
	}
}

发送请求后,我得到了以下响应:

curl localhost:3000/hello
{"message":"World"}
{"message":"Hello"}

我的目标是生成以下响应:

{"message":"Hello World"}

echo.Context具有实现ResponseWriter的Response结构体。

但是,ResponseWriter似乎是只写的协议。有没有办法在ResponseWriter中擦除和重建数据?

据我所见,存在两个问题:

1)在传递“middle”处理程序后从ResponseWriter读取数据。
2)在“handler”处理程序中擦除ResponseWriter中的数据并写入新数据。

在实际问题中,结构体的名称冲突并不重要。这是对两个不同的SCIM API的请求,并将其组合成响应。

英文:

I use echo framework in my app and i faced with issue to constuct response from two handler on single entrypoint.

There is example code

type RespObject struct {
	Message string `json:"message"`
}

func main() {
	e := echo.New()
	e.GET("/hello", handler, middle)

	e.Logger.Fatal(e.Start(":3000"))
}

func handler(c echo.Context) error {
	return c.JSON(http.StatusOK, RespObject{
		Message: "Hello",
	})
}

func middle(next echo.HandlerFunc) echo.HandlerFunc {
	return func(c echo.Context) error {
		c.JSON(http.StatusOK, RespObject{
			Message: "World",
		})
		return next(c)
	}
}

after request i got

curl localhost:3000/hello
{"message":"World"}
{"message":"Hello"}

My goal is make response

{"message":"Hello World"}

echo.Context has struct Response with implement ResponseWriter

But seems ResponseWriter is WriteOnly contract. Is there is a way to some how erase and rebuild data in ResponseWriter?

As far i see there is a two issues

  1. Read data from ResponseWriter after passing "middle" handler.
  2. Erase data in ResponseWriter and write new data in "handler" handler

In real issue there is not necessary of name collision of struct. It`s request in two different SCIM API and make combine response.

答案1

得分: 3

这可以通过创建一个自定义函数来实现,该函数将响应对象和代码添加到上下文中,并在处理程序中调用它;在中间件中,您可以从上下文中获取此对象,修改响应并调用实际的c.JSON,将修改后的响应写入网络。

const (
    echoCtxRespKey = "echo_ctx_resp_key"
)

type RespObject struct {
    Message string `json:"message"`
}

type Response struct {
    Data interface{}
    Code int
}

func main() {
    e := echo.New()
    e.GET("/hello", handler, middle)

    e.Logger.Fatal(e.Start(":3000"))
}

func handler(c echo.Context) error {
    resp := RespObject{
        Message: "Hello",
    }
    addResponseToContext(c, Response{
        Data: resp,
        Code: http.StatusOK,
    })

    return nil
}

func middle(next echo.HandlerFunc) echo.HandlerFunc {
    return func(c echo.Context) error {
        next(c)

        resp := getResponseFromContext(c)

        // modify resp

        return c.JSON(resp.Code, resp.Data)
    }
}

func addResponseToContext(c echo.Context, response Response) {
    c.Set(echoCtxRespKey, response)
}

func getResponseFromContext(c echo.Context) Response {
    return c.Get(echoCtxRespKey).(Response)
}

以上是您提供的代码的翻译。

英文:

This can be achieved by creating a custom function that adds the response object and code to context and call it in handler; in middleware you get this object from context, modify the response and call actual c.JSON which writes the modified response to the wire.

const (
	echoCtxRespKey = "echo_ctx_resp_key"
)

type RespObject struct {
	Message string `json:"message"`
}

type Response struct {
	Data interface{}
	Code int
}

func main() {
	e := echo.New()
	e.GET("/hello", handler, middle)

	e.Logger.Fatal(e.Start(":3000"))
}

func handler(c echo.Context) error {
	resp := RespObject{
		Message: "Hello",
	}
	addResponseToContext(c, Response{
		Data: resp,
		Code: http.StatusOK,
	})
	
	return nil 
}

func middle(next echo.HandlerFunc) echo.HandlerFunc {
	return func(c echo.Context) error {
		next(c)
		
		resp := getResponseFromContext(c)
		
		// modify resp
		
		return c.JSON(resp.Code, resp.Data)
	}
}

func addResponseToContext(c echo.Context, response Response) {
	c.Set(echoCtxRespKey, response)
}

func getResponseFromContext(c echo.Context) Response {
	return c.Get(echoCtxRespKey).(Response)
}

huangapple
  • 本文由 发表于 2022年9月4日 02:40:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/73594639.html
匿名

发表评论

匿名网友

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

确定