Golang Echo分别绑定路径参数和JSON请求体

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

Golang Echo bind path param and json body separately

问题

我正在使用Golang中的Echo Web框架,并编写了以下代码:

package main

import (
	"github.com/labstack/echo/v4"
	"net/http"
)

type ProjectPath struct {
	ID string `param:"id"`
}

type ProjectBody struct {
	Name string `json:"name"`
}

func main() {
	e := echo.New()

	e.POST("/project/:id", getProjectHandler)

	e.Start(":8080")
}

func getProjectHandler(c echo.Context) error {
	path := new(ProjectPath)
	if err := c.Bind(path); err != nil {
		return err
	}

	body := new(ProjectBody)
	if err := c.Bind(body); err != nil {
		return err
	}

	// 分别访问路径参数和JSON体字段
	projectID := path.ID
	projectName := body.Name

	// 使用路径参数和JSON体字段进行操作...

	// 返回响应
	return c.String(http.StatusOK, "项目ID:"+projectID+",项目名称:"+projectName)
}

我尝试在POST请求中分别绑定路径参数和JSON体,但在运行时遇到了EOF错误。

我正在使用replit进行测试,服务器运行在:https://echotest.sandeepacharya.repl.co

Curl POST请求:

curl -X POST https://echotest.sandeepacharya.repl.co/project/123 -H "Content-Type: application/json" -d '{"name":"Sandeep"}'

响应:

{"message":"EOF"}
英文:

I am using Echo web framework in Golang and I wrote this code

package main

import (
	"github.com/labstack/echo/v4"
	"net/http"
)

type ProjectPath struct {
	ID string `param:"id"`
}

type ProjectBody struct {
	Name string `json:"name"`
}

func main() {
	e := echo.New()

	e.POST("/project/:id", getProjectHandler)

	e.Start(":8080")
}

func getProjectHandler(c echo.Context) error {
	path := new(ProjectPath)
	if err := c.Bind(path); err != nil {
		return err
	}

	body := new(ProjectBody)
	if err := c.Bind(body); err != nil {
		return err
	}

	// Access the fields separately
	projectID := path.ID
	projectName := body.Name

	// Do something with the path and body fields...

	// Return a response
	return c.String(http.StatusOK, "Project ID: "+projectID+", Project Name: "+projectName)
}

I am trying to bind a path param and json body separately in a post request but I am getting an EOF error while trying to run it.

I am using replit for testing and the server is running on: https://echotest.sandeepacharya.repl.co

Curl Post Request:

 curl -X POST https://echotest.sandeepacharya.repl.co/project/123 -H "Content-Type: application/json" -d '{"name":"Sandeep"}'

Response:

{"message":"EOF"}

答案1

得分: 2

如果您想要单独进行绑定,那么您需要使用特定于源的绑定方法。然而,这些方法在上下文中是不可用的,而是由DefaultBinder实现。

请参考:https://echo.labstack.com/guide/binding/#direct-source

func getProjectHandler(c echo.Context) error {
    path := new(ProjectPath)
    if err := (&echo.DefaultBinder{}).BindPathParams(c, path); err != nil {
        return err
    }

    body := new(ProjectBody)
    if err := (&echo.DefaultBinder{}).BindBody(c, body); err != nil {
        return err
    }

    // 分别访问字段
    projectID := path.ID
    projectName := body.Name

    // 使用路径和请求体字段进行操作...

    // 返回响应
    return c.String(http.StatusOK, "项目ID:"+projectID+",项目名称:"+projectName)
}
英文:

If you want to do the binding separately then you'll need to use the source specific bind methods. These methods however are NOT available in the context, instead they are implemented by the DefaultBinder.

See also: https://echo.labstack.com/guide/binding/#direct-source

func getProjectHandler(c echo.Context) error {
    path := new(ProjectPath)
    if err := (&echo.DefaultBinder{}).BindPathParams(c, path); err != nil {
        return err
    }

    body := new(ProjectBody)
    if err := (&echo.DefaultBinder{}).BindBody(c, body); err != nil {
        return err
    }

    // Access the fields separately
    projectID := path.ID
    projectName := body.Name

    // Do something with the path and body fields...

    // Return a response
    return c.String(http.StatusOK, "Project ID: "+projectID+", Project Name: "+projectName)
}

答案2

得分: 1

问题的原因是您尝试两次绑定请求体。第二个c.Bind()会引发错误,因为请求体已经被读取和消耗掉了。

如果您想使用不同的结构体读取请求,可以按照以下方法进行操作:

package main

import (
	"fmt"
	"net/http"

	"github.com/labstack/echo/v4"
)

type ProjectPath struct {
	ID string `param:"id"`
}

type ProjectBody struct {
	Name string `json:"name"`
}

type ProjectRequest struct {
	ProjectPath
	ProjectBody
}

func main() {
	e := echo.New()

	e.POST("/project/:id", getProjectHandler)

	e.Start(":8080")
}

func getProjectHandler(c echo.Context) error {

	project := new(ProjectRequest)
	if err := c.Bind(project); err != nil {
		fmt.Println("Error happened due to:", err)
		return err
	}

	// 分别访问字段
	projectID := project.ID
	projectName := project.Name

	// 对路径和请求体字段进行处理...

	// 返回响应
	return c.String(http.StatusOK, "Project ID: "+projectID+", Project Name: "+projectName)
}

或者您可以使用一个结构体来绑定请求:

type ProjectRequest struct {
	Name string `json:"name"`
	ID string `param:"id"`
}
英文:

> Bind() reads request body directly from the socket and once read it can't read again, hence the EOF error

https://github.com/labstack/echo/issues/782#issuecomment-317503513

The issue is occured due to that you are attempted to bind the request body twice. The second c.Bind() will raise an error because the request body has already been read and consumed.

if you want to read the request with different struct, you can follow this approach

package main

import (
	"fmt"
	"net/http"

	"github.com/labstack/echo/v4"
)

type ProjectPath struct {
	ID string `param:"id"`
}

type ProjectBody struct {
	Name string `json:"name"`
}

type ProjectRequest struct {
	ProjectPath
	ProjectBody
}

func main() {
	e := echo.New()

	e.POST("/project/:id", getProjectHandler)

	e.Start(":8080")
}

func getProjectHandler(c echo.Context) error {

	project := new(ProjectRequest)
	if err := c.Bind(project); err != nil {
		fmt.Println("Error happened due to::", err)
		return err
	}

	// Access the fields separately
	projectID := project.ID
	projectName := project.Name

	// Do something with the path and body fields...

	// Return a response
	return c.String(http.StatusOK, "Project ID: "+projectID+", Project Name: "+projectName)
}

or you can use only one struct to bind the request

type ProjectRequest struct {
	Name string `json:"name"`
	ID string `param:"id"`
}

huangapple
  • 本文由 发表于 2023年7月1日 18:06:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76594176.html
匿名

发表评论

匿名网友

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

确定