Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/ghttp:Improve the process of parameter parsing #3578

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
13 changes: 8 additions & 5 deletions net/ghttp/ghttp.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,14 @@ type (

// handlerFuncInfo contains the HandlerFunc address and its reflection type.
handlerFuncInfo struct {
Func HandlerFunc // Handler function address.
Type reflect.Type // Reflect type information for current handler, which is used for extensions of the handler feature.
Value reflect.Value // Reflect value information for current handler, which is used for extensions of the handler feature.
IsStrictRoute bool // Whether strict route matching is enabled.
ReqStructFields []gstructs.Field // Request struct fields.
Func HandlerFunc // Handler function address.
Type reflect.Type // Reflect type information for current handler, which is used for extensions of the handler feature.
Value reflect.Value // Reflect value information for current handler, which is used for extensions of the handler feature.
IsStrictRoute bool // Whether strict route matching is enabled.
ReqStructFields []gstructs.Field // Request struct fields.
defaultTagFields []gstructs.Field // Language string `d:"go"`
inTagFields []gstructs.Field // Language string `in:"header"`
hasValidTagFields bool
}

// HandlerItem is the registered handler for route handling,
Expand Down
6 changes: 6 additions & 0 deletions net/ghttp/ghttp_request_param.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ func (r *Request) doParse(pointer interface{}, requestType int) error {
return err
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这3个case对应的方法其实存在瑕疵:

  • mergeInTagStructValue仅在doGetRequestStruct中有处理,其他两个case没有处理。
  • 这3个方法都重复调用了mergeDefaultStructValue方法,其实可以抽象出来统一处理。

}
}
funcInfo := r.serveHandler.Handler.Info
if funcInfo.IsStrictRoute {
if funcInfo.hasValidTagFields == false {
return nil
}
}
// TODO: https://github.com/gogf/gf/pull/2450
// Validation.
if err = gvalid.New().
Expand Down
4 changes: 2 additions & 2 deletions net/ghttp/ghttp_request_param_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ func (r *Request) doGetRequestStruct(pointer interface{}, mapping ...map[string]

// mergeDefaultStructValue merges the request parameters with default values from struct tag definition.
func (r *Request) mergeDefaultStructValue(data map[string]interface{}, pointer interface{}) error {
fields := r.serveHandler.Handler.Info.ReqStructFields
fields := r.serveHandler.Handler.Info.defaultTagFields
if len(fields) > 0 {
var (
foundKey string
Expand Down Expand Up @@ -240,7 +240,7 @@ func (r *Request) mergeDefaultStructValue(data map[string]interface{}, pointer i

// mergeInTagStructValue merges the request parameters with header or cookie values from struct `in` tag definition.
func (r *Request) mergeInTagStructValue(data map[string]interface{}, pointer interface{}) error {
fields := r.serveHandler.Handler.Info.ReqStructFields
fields := r.serveHandler.Handler.Info.inTagFields
if len(fields) > 0 {
var (
foundKey string
Expand Down
56 changes: 56 additions & 0 deletions net/ghttp/ghttp_server_service_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ func (s *Server) checkAndCreateFuncInfo(
return funcInfo, err
}
funcInfo.ReqStructFields = fields
parseStructFields(&funcInfo)
funcInfo.Func = createRouterFunc(funcInfo)
return
}
Expand Down Expand Up @@ -305,6 +306,61 @@ func createRouterFunc(funcInfo handlerFuncInfo) func(r *Request) {
}
}

func parseStructFields(funcInfo *handlerFuncInfo) {
reqStructType := funcInfo.Type.In(1)
reqStructType = reqStructType.Elem()

for i := 0; i < len(funcInfo.ReqStructFields); i++ {
field := funcInfo.ReqStructFields[i]
defaultTag := field.TagDefault()
if defaultTag != "" {
funcInfo.defaultTagFields = append(funcInfo.defaultTagFields, field)
}
inTag := field.TagIn()
if inTag != "" {
funcInfo.inTagFields = append(funcInfo.inTagFields, field)
}
validTag := field.TagValid()
if validTag == "" {
// Check for recursively nested structs
funcInfo.hasValidTagFields = checkFieldsHasValidTag(field.Field.Type)
} else {
funcInfo.hasValidTagFields = true
}
gqcn marked this conversation as resolved.
Show resolved Hide resolved
}
}

func checkFieldsHasValidTag(field reflect.Type) (has bool) {
if field.Kind() == reflect.Ptr {
field = field.Elem()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这样获取field的原始类型并不准确,可以给Field结构体增加OriginalType方法,参考现有的OriginalKind实现:

func (f *Field) OriginalKind() reflect.Kind {

}
switch field.Kind() {
// []*struct or map[key]*struct
case reflect.Slice, reflect.Map, reflect.Array:
field = field.Elem()
}
if field.Kind() == reflect.Ptr {
field = field.Elem()
}
if field.Kind() != reflect.Struct {
return
}

for i := 0; i < field.NumField(); i++ {
f := field.Field(i)
tag := f.Tag.Get("v")
if tag == "" {
tag = f.Tag.Get("valid")
}
if tag != "" {
return true
}
has = checkFieldsHasValidTag(f.Type)
}

return
}

// trimGeneric removes type definitions string from response type name if generic
func trimGeneric(structName string) string {
var (
Expand Down
2 changes: 1 addition & 1 deletion net/ghttp/ghttp_z_unit_issue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func (r cFoo1) PostTest1(ctx context.Context, req *TemplateCreateReq) (res *Temp
}

// https://github.com/gogf/gf/issues/1662
func Test_Issue662(t *testing.T) {
func Test_Issue1662(t *testing.T) {
s := g.Server(guid.S())
s.Use(ghttp.MiddlewareHandlerResponse)
s.Group("/boot", func(grp *ghttp.RouterGroup) {
Expand Down