如何通过反射校验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 }
代码说明
- 指针类型兼容:因为
InputAccount的字段都是指针类型,先通过rt.Elem()获取指针指向的原始类型(如*int对应int),避免断言指针类型导致的错误。 - JSON数字适配:Go的
json.Unmarshal会将JSON中的整数解析为float64,所以校验整数类型时需断言为float64而非原生int。 - 错误收集:遍历所有必填字段,收集所有类型不匹配的错误信息,返回错误列表便于后续组装提示返回给用户。
使用示例
// 构造测试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
相关产品推荐
相关产品推荐

