You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过反射校验JSON HTTP请求的字段数据类型错误

完善Go中JSON字段数据类型校验函数

需求:当JSON请求体存在语义错误时,返回包含数据类型错误字段的有效提示(无需校验字段是否存在)。已有以下实现代码,需完善invalid_fields_data_type函数,添加类型断言逻辑校验已存在字段的数据类型是否符合要求。

已有实现代码

1. 解析JSON请求体为map[string]any的函数

import "encoding/json"
import "fmt"

func get_request_body_fields(b []byte) (map[string]any, error){
    var body any
    if err := json.Unmarshal(b, &body); err != nil {
        return nil, fmt.Errorf("Request body must be key-value pairs")
    }
    fields, ok := body.(map[string]any)
    if !ok {
        return nil, fmt.Errorf("Request body must be key-value pairs")
    }
    return fields, nil
}

2. 通过反射从结构体获取必填字段类型的函数

import "reflect"
import "strings"

func required_input_fields_elem(elem reflect.Value) (map[string]reflect.Type, error){
    list := map[string]reflect.Type{}
    if elem.Kind() != reflect.Struct {
        return nil, fmt.Errorf("Input must be a struct")
    }
    struct_val := elem.Type()
    for i := 0; i < struct_val.NumField(); i++ {
        field := struct_val.Field(i)
        list[strings.ToLower(field.Name)] = field.Type
    }
    return list, nil
}

3. 待完善的结构体定义与校验函数

// 必填字段结构体
type InputAccount struct {
    Account_number  *int        `json:"account_number"`
    Name            *string     `json:"name"`
    Type            *string     `json:"type"`
    Vatcode_name    *string     `json:"vatcode_name"`
}

完善后的校验函数

import "fmt"

func invalid_fields_data_type(required_fields map[string]reflect.Type, body_fields map[string]any) []string {
    var typeErrors []string
    for field, rt := range required_fields {
        bodyField, exists := body_fields[field]
        if !exists {
            continue // 无需校验字段是否存在,直接跳过
        }

        // 处理结构体字段的指针类型(如*int、*string)
        targetType := rt
        if rt.Kind() == reflect.Ptr {
            targetType = rt.Elem()
        }

        // 针对不同目标类型做类型断言校验
        switch targetType.Kind() {
        case reflect.Int:
            // JSON解析数字默认是float64,需特殊处理
            if _, ok := bodyField.(float64); !ok {
                typeErrors = append(typeErrors, fmt.Sprintf("字段%s类型错误:期望整数,实际为%T", field, bodyField))
            }
        case reflect.String:
            if _, ok := bodyField.(string); !ok {
                typeErrors = append(typeErrors, fmt.Sprintf("字段%s类型错误:期望字符串,实际为%T", field, bodyField))
            }
        // 可扩展支持其他类型,如bool、float32等
        }
    }
    return typeErrors
}

代码说明

  1. 指针类型兼容:因为InputAccount的字段都是指针类型,先通过rt.Elem()获取指针指向的原始类型(如*int对应int),避免断言指针类型导致的错误。
  2. JSON数字适配:Go的json.Unmarshal会将JSON中的整数解析为float64,所以校验整数类型时需断言为float64而非原生int。
  3. 错误收集:遍历所有必填字段,收集所有类型不匹配的错误信息,返回错误列表便于后续组装提示返回给用户。

使用示例

// 构造测试JSON
testJSON := []byte(`{"account_number": "12345", "name": 6789}`)
bodyFields, _ := get_request_body_fields(testJSON)
requiredFields, _ := required_input_fields_elem(reflect.ValueOf(InputAccount{}))

// 执行校验
errors := invalid_fields_data_type(requiredFields, bodyFields)
for _, err := range errors {
    fmt.Println(err)
}
// 输出结果:
// 字段account_number类型错误:期望整数,实际为string
// 字段name类型错误:期望字符串,实际为float64

内容的提问来源于stack exchange,提问作者clarkk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 19:03:21