gin/golang validator 空值验证

431 阅读2分钟

问题

在日常需求中经常会有更新部分参数的需求,比如一个人的name、age、salary 前端可能只更新age字段,这时候发送的json通常是这样的

{"age":12}

这时候在gin/golang端的验证结构体则是这样的 ``

type UpdateParams struct {
    Name   string `json:"name" binding:"omitempty,gt=0,lte=50" label:"名字"`
    Age  int    `json:"age" binding:"omitempty,gt=0" label:"年龄"`
    Salary  int    `json:"salary" binding:"omitempty,gt=0" label:"薪水"`
}

但是这样存在的问题就是,如果用户不小心设置成0,数据验证时同样不会报错,因为omitempty标签允许字段为空字符串("")或零值(如0)。虽然age被设置为0,但是被omitempty认为是未设置,所以gt标签根本不会验证。同时age又不能设置成required,所以这样就造成了一定的漏洞。 同样的问题也会发生在name字段,如果前端发送json

{"name":""}

情况和age一样,空字符串也被当做未设置该字段,从而验证通过,造成了漏洞。这个问题在字段少的时候可以通过将每个字段都设置成required来强制前端发送每个字段,但是如果有很多字段就不太现实了。

解决办法

将gin/golang端的结构字段都修改成指针

type UpdateParams struct {
    Name   *string `json:"name" binding:"omitempty,gt=0,lte=50" label:"名字"`
    Age  *int    `json:"age" binding:"omitempty,gt=0" label:"年龄"`
    Salary  *int    `json:"salary" binding:"omitempty,gt=0" label:"薪水"`
}

解决原理

在Go语言中nil值可以表示“未设置”或“无值”。

  1. omitempty标签的含义:

    • 当字段类型为非指针类型时,omitempty标签允许字段为空字符串("")或零值(如0),而不是未设置。
    • 当字段类型为指针类型时,omitempty标签允许字段为nil,表示字段未设置。
  2. omitempty标签与指针类型的结合:

    • 当您使用指针类型时,如果字段未设置(即前端发送的数据中没有这个字段),那么绑定到结构体时,对应的指针字段将会是nil
    • 如果字段被设置了,那么对应的指针字段将会指向一个非nil的值,此时该值就能被后面的标签处理了。
    • 因此,omitempty标签可以正确地处理指针类型的字段,区分“未设置”和“设置了但为零值”的情况。

以上是综合多方搜索之后的结果,各位大佬如果有更好的解决办法、不同的观点,欢迎评论指正。