[gogf/gf]参数绑定时若数据类型不一致可否报错无需使用默认类型零值

2024-06-25 550 views
8
1. 您使用的是什么版本Go和系统类型/架构?

go 版本 go1.18.3 linux/amd64

2. 您使用的是什么版本GoFrame

v2.2.4

3. 最新版本的版本还会重现这个问题吗?

是的

4. 你做了什么?
package main

import (
    "context"
    "fmt"

    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/net/ghttp"
)

type HelloReq struct {
    g.Meta `path:"/hello/{ID}" method:"get"`
    ID     int `v:"required"`
}
type HelloRes struct {
    Reply string `dc:"Reply content"`
}

type Hello struct{}

func (Hello) Say(ctx context.Context, req *HelloReq) (res *HelloRes, err error) {
    g.Log().Debug(ctx, err)
    res = &HelloRes{
        Reply: fmt.Sprintf(`Hi %d`, req.ID),
    }
    return
}

func main() {
    s := g.Server()
    s.Use(ghttp.MiddlewareHandlerResponse)
    s.Group("/", func(group *ghttp.RouterGroup) {
        group.Bind(
            new(Hello),
        )
    })
    s.Run()
}
5. 你期望看到什么?

用户发送短信验证码时直接报错400,流程停止

6. 你看到的是什么?

没有报错,返回零值0

$ curl http://localhost:62866/hello/xyz
{"code":0,"message":"","data":{"Reply":"Hi 0"}}

$ curl http://localhost:62866/hello/1
{"code":0,"message":"","data":{"Reply":"Hi 1"}}

感觉好处有两点:

  1. 快速报告错误方便客户端调整参数类型
  2. 接口的解析一定正确,不需要为零值

回答

2

改写成 v:"required|integer|gt:0"

4

感谢感谢,使用 v:"integer" 确实可以,就是每次为了校验数据类型都写 tag 可能有点麻烦😢

4

入参类型本身就是需要进行验证的,以下内容均来自互联网。不能依赖错误去决定处理逻辑,而应该做的是不要犯错误的错误。

8

暂时先关闭了,麻烦请重新打开。

0
杜松子酒

在 gin 中数据绑定时不需要再使用 tag 重复声明数据类型的

package main

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

type HelloReq struct {
    ID int `json:"id" bind:"required"`
}

func main() {
    r := gin.Default()

    r.POST("/hello", func(c *gin.Context) {
        var param HelloReq

        if err := c.ShouldBindJSON(&param); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
            return
        }

        c.JSON(http.StatusOK, gin.H{"msg": "success"})
    })

    r.Run("localhost:6666")
}

图像

可以看到如果客户端传递字符串会有提示信息

女朋友
package main

import (
    "context"
    "fmt"

    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/net/ghttp"
)

type HelloReq struct {
    g.Meta `path:"/hello" method:"post"`
    ID     int `v:"required"`
}
type HelloRes struct {
    Reply string `dc:"Reply content"`
}

type Hello struct{}

func (Hello) Say(ctx context.Context, req *HelloReq) (res *HelloRes, err error) {
    res = &HelloRes{
        Reply: fmt.Sprintf(`Hi %d`, req.ID),
    }
    return
}

func main() {
    s := g.Server()
    s.SetAddr("localhost:8000")
    s.Use(ghttp.MiddlewareHandlerResponse)
    s.Group("/", func(group *ghttp.RouterGroup) {
        group.Bind(
            new(Hello),
        )
    })
    s.Run()
}

图像

我理解在定义结构体时已经表明ID是int类型了,但是还要再使用v:"interger"来约束类型,有种重复的感觉,如果忘记加约束,默认使用类型零值可能会引起困惑。

5

假设检验方法是随机的,先校验身份后验证是否正确,再进行校验。在gf中bind对应的标签应该是p,与v标签互相独立。 @gqcn 这个你来看下?