使用 http Mux 请求正文验证

Posted

技术标签:

【中文标题】使用 http Mux 请求正文验证【英文标题】:Request body validation with http Mux 【发布时间】:2020-07-25 14:18:22 【问题描述】:

我正在尝试使用 Go 和 Mux 构建 API。我正在尝试验证传入的请求。我尝试在 Struct 上使用标签并使用 Go Validator 对其进行验证。

这是我的结构

type Address struct 
    Street string `validate:"required"`
    City   string `validate:"required"`
    Phone  string `validate:"required"`

我的问题是

有一个POST 端点,所有字段都将通过并且验证不会失败。但是,还有另一个 PATCH 端点,并非 Address 结构的所有字段都会通过,因此验证失败。

例如。 API 可能会收到


  "Street": "Dummy"

在这种情况下验证POSTPATCH 请求的最佳方法是什么。

【问题讨论】:

【参考方案1】:

在 PATCH 端点中使用具有不同(如果有)验证标签的不同类型。之后转换为地址:

// Same underlying type as Address, but no validation tags
var x struct 
    Street string
    City   string
    Phone  string


// Decode request into x, then:

addr := Address(x)

【讨论】:

谢谢。在这种情况下,如果我们添加一个新字段,那么我们必须在所有正确创建的类型中更改它。 是的。编译器会确保你不会忘记一个。【参考方案2】:

改变我的答案

我已经对您的案例进行了测试并找到了解决方案,您必须使用struct level validation。这是我在您的案例中的功能:

func PostRequestValidation(sl validator.StructLevel) 

    address := sl.Current().Interface().(Address)

    jsonMarshal, _ := json.Marshal(address)
    var m map[string]interface
    _ = json.Unmarshal(jsonMarshal, &m)
    for key, val := range m 
        if len(fmt.Sprintf("%s", val)) == 0 
            sl.ReportError(val, key, key, "post", "")
        
    


func PutRequestValidation(sl validator.StructLevel) 

    address := sl.Current().Interface().(Address)

    isValid := false

    jsonMarshal, _ := json.Marshal(address)
    var m map[string]interface
    _ = json.Unmarshal(jsonMarshal, &m)
    for _, val := range m 
        if len(fmt.Sprintf("%s", val)) > 0 
            isValid = true
        
    

    if !isValid 
        sl.ReportError(address, "address", "Adress", "put", "")
    

您只需在每个验证请求上注册

    // ON POST REQUEST
    validate = validator.New()
    validate.RegisterTagNameFunc(func(fld reflect.StructField) string 
        name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
        if name == "-" 
            return ""
        
        return name
    )
    validate.RegisterStructValidation(PostRequestValidation, Address)
    // ON PUT REQUEST
    validate = validator.New()
    validate.RegisterTagNameFunc(func(fld reflect.StructField) string 
        name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
        if name == "-" 
            return ""
        
        return name
    )
    validate.RegisterStructValidation(PutRequestValidation, Address)

您可以从我的source code 复制以获得更详细的源代码。

【讨论】:

感谢您的指点。但是使用上述方法之一会使 POST 请求无效,因为在 POST 中我们需要所有字段。这里有什么建议吗? aha,所以如果你需要多个这样的条件,你可以使用 Or 运算符。以街道字符串 validate:"required|required_without_all" 为例。替换每个字段的验证。我将根据此评论更新我的答案。您应该根据评论更新您的问题。 我已经更新了这个问题。现在说清楚了:) 这仍然不起作用 - or 条件无法正确评估。说PATCH 我不需要City,但POST 需要City。即使未提供 City,使用 or 条件也可以验证 POST 有效负载。 嗨,我希望你可以根据你的需要修改我的代码,对不起我之前的回答,它具有误导性。如果您回答了这个问题,请不要忘记将此问题标记为已解决。【参考方案3】:

找到这个库 - govalidator。这允许根据要求为每个请求创建规则。对于 POST 请求,创建一组规则,所有字段均为必填项。对于 PATCH 请求,创建所有字段为可选的规则。

【讨论】:

以上是关于使用 http Mux 请求正文验证的主要内容,如果未能解决你的问题,请参考以下文章

如何在单元测试中验证Flurl Http中的请求正文内容?

在 Azure API 管理器中验证 POST 请求正文

使用 webargs 验证 AWS lambda 中的查询字符串参数和请求正文

如何在 NestJS 控制器处理程序的请求中获取“已验证的正文”和“已验证的用户”?

如何使用 MockWebServer 验证 POST 正文的内容?

有没有办法将 Authorize 属性与没有身份验证标头的请求一起使用?