// Package codec provides encoding and decoding utilities across various formats package codec import ( "errors" "fmt" "net/http" "reflect" ) func decodeTo(r *http.Request, val any) error { rt := reflect.TypeOf(val).Elem() rv := reflect.ValueOf(val).Elem() fields, err := getStructFields(rt, rv) if err != nil { return err } formCodec, err := NewFormCodec(r) if err != nil { return err } pathCodec := NewPathCodec(r) queryCodec := NewQueryCodec(r) headerCodec := NewHeaderCodec(r) for _, f := range fields { switch f.tag.In { case pathOptName: if err := pathCodec.Decode(f.field, f.fv, f.tag); err != nil { return fmt.Errorf("field[%s] decode path: %w", f.field.Name, err) } case queryOptName: if err := queryCodec.Decode(f.field, f.fv, f.tag); err != nil { return fmt.Errorf("field[%s] decode query: %w", f.field.Name, err) } case formOptName: if err := formCodec.Decode(f.field, f.fv, f.tag); err != nil { return fmt.Errorf("field[%s] decode form: %w", f.field.Name, err) } case headerOptName: if err := headerCodec.Decode(f.field, f.fv, f.tag); err != nil { return fmt.Errorf("field[%s] decode header: %w", f.field.Name, err) } case "": return fmt.Errorf("field[%s] in option is required", f.field.Name) default: return fmt.Errorf("field[%s] in[%s] option not valid", f.field.Name, f.tag.In) } } // json 整个解析 jsonCodec := NewJsonCodec(r) if err := jsonCodec.Decode(val); err != nil { return fmt.Errorf("decode json: %w", err) } return nil } // Decode 按结构体反序列化Request func Decode[T any](r *http.Request) (*T, error) { rt := reflect.TypeFor[T]() if rt.Kind() != reflect.Struct { return nil, errors.New("generic type T must be a struct type") } t := new(T) err := decodeTo(r, t) if err != nil { return nil, fmt.Errorf("decode req: %w", err) } return t, nil } type structField struct { field reflect.StructField // 结构体字段 fv reflect.Value // 字段的值 tag *Tag // 字段解析后的req tag } // getStructFields 获取字段列表, 校验json/req的唯一性 func getStructFields(rt reflect.Type, rv reflect.Value) ([]structField, error) { fields := make([]structField, 0) for i := 0; i < rt.NumField(); i++ { field := rt.Field(i) // 非导出需要跳过, 无法设置值 if !field.IsExported() { continue } reqTagStr := field.Tag.Get(tagName) if reqTagStr == "" { continue } tag, err := parseTag(reqTagStr) if err != nil { return nil, fmt.Errorf("field[%s] %w", field.Name, err) } // tag name为空或者-忽略 if tag.Name == "" || tag.Name == "-" { continue } // 可以重复 // jsonTagName := util.GetTagName(field, "json") // if jsonTagName != "" && jsonTagName != "-" { // return nil, fmt.Errorf("field[%s] req and json tag are mutually exclusive", field.Name) // } fields = append(fields, structField{field: field, fv: rv.Field(i), tag: tag}) } return fields, nil } // getFieldValue 获取字段值 func getFieldValue(field reflect.Type, tag *Tag, values []string) (reflect.Value, error) { // 指针类型 if field.Kind() == reflect.Pointer { typ := field.Elem() rv, err := getFieldValue(typ, tag, values) if err != nil { return reflect.Value{}, err } newPtr := reflect.New(typ) newPtr.Elem().Set(rv) return newPtr, nil } // slice类型 if field.Kind() == reflect.Slice { typ := field.Elem() // []byte 特殊处理 if typ == byteType { return ParseValue(field, values[0], tag.Option) } val := reflect.MakeSlice(field, 0, len(values)) for _, v := range values { rv, err := getFieldValue(typ, tag, []string{v}) if err != nil { return reflect.Value{}, err } val = reflect.Append(val, rv) } return val, nil } return ParseValue(field, values[0], tag.Option) }