github.com/wangyougui/gf/v2@v2.6.5/net/ghttp/ghttp_request_param_request.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/wangyougui/gf.
     6  
     7  package ghttp
     8  
     9  import (
    10  	"github.com/wangyougui/gf/v2/container/gvar"
    11  	"github.com/wangyougui/gf/v2/internal/empty"
    12  	"github.com/wangyougui/gf/v2/net/goai"
    13  	"github.com/wangyougui/gf/v2/os/gstructs"
    14  	"github.com/wangyougui/gf/v2/util/gconv"
    15  	"github.com/wangyougui/gf/v2/util/gutil"
    16  )
    17  
    18  // GetRequest retrieves and returns the parameter named `key` passed from the client and
    19  // custom params as interface{}, no matter what HTTP method the client is using. The
    20  // parameter `def` specifies the default value if the `key` does not exist.
    21  //
    22  // GetRequest is one of the most commonly used functions for retrieving parameters.
    23  //
    24  // Note that if there are multiple parameters with the same name, the parameters are
    25  // retrieved and overwrote in order of priority: router < query < body < form < custom.
    26  func (r *Request) GetRequest(key string, def ...interface{}) *gvar.Var {
    27  	value := r.GetParam(key)
    28  	if value.IsNil() {
    29  		value = r.GetForm(key)
    30  	}
    31  	if value.IsNil() {
    32  		r.parseBody()
    33  		if len(r.bodyMap) > 0 {
    34  			if v := r.bodyMap[key]; v != nil {
    35  				value = gvar.New(v)
    36  			}
    37  		}
    38  	}
    39  	if value.IsNil() {
    40  		value = r.GetQuery(key)
    41  	}
    42  	if value.IsNil() {
    43  		value = r.GetRouter(key)
    44  	}
    45  	if !value.IsNil() {
    46  		return value
    47  	}
    48  	if len(def) > 0 {
    49  		return gvar.New(def[0])
    50  	}
    51  	return nil
    52  }
    53  
    54  // GetRequestMap retrieves and returns all parameters passed from the client and custom params
    55  // as the map, no matter what HTTP method the client is using. The parameter `kvMap` specifies
    56  // the keys retrieving from client parameters, the associated values are the default values
    57  // if the client does not pass the according keys.
    58  //
    59  // GetRequestMap is one of the most commonly used functions for retrieving parameters.
    60  //
    61  // Note that if there are multiple parameters with the same name, the parameters are retrieved
    62  // and overwrote in order of priority: router < query < body < form < custom.
    63  func (r *Request) GetRequestMap(kvMap ...map[string]interface{}) map[string]interface{} {
    64  	r.parseQuery()
    65  	r.parseForm()
    66  	r.parseBody()
    67  	var (
    68  		ok, filter bool
    69  	)
    70  	if len(kvMap) > 0 && kvMap[0] != nil {
    71  		filter = true
    72  	}
    73  	m := make(map[string]interface{})
    74  	for k, v := range r.routerMap {
    75  		if filter {
    76  			if _, ok = kvMap[0][k]; !ok {
    77  				continue
    78  			}
    79  		}
    80  		m[k] = v
    81  	}
    82  	for k, v := range r.queryMap {
    83  		if filter {
    84  			if _, ok = kvMap[0][k]; !ok {
    85  				continue
    86  			}
    87  		}
    88  		m[k] = v
    89  	}
    90  	for k, v := range r.formMap {
    91  		if filter {
    92  			if _, ok = kvMap[0][k]; !ok {
    93  				continue
    94  			}
    95  		}
    96  		m[k] = v
    97  	}
    98  	for k, v := range r.bodyMap {
    99  		if filter {
   100  			if _, ok = kvMap[0][k]; !ok {
   101  				continue
   102  			}
   103  		}
   104  		m[k] = v
   105  	}
   106  	for k, v := range r.paramsMap {
   107  		if filter {
   108  			if _, ok = kvMap[0][k]; !ok {
   109  				continue
   110  			}
   111  		}
   112  		m[k] = v
   113  	}
   114  	// File uploading.
   115  	if r.MultipartForm != nil {
   116  		for name := range r.MultipartForm.File {
   117  			if uploadFiles := r.GetUploadFiles(name); len(uploadFiles) == 1 {
   118  				m[name] = uploadFiles[0]
   119  			} else {
   120  				m[name] = uploadFiles
   121  			}
   122  		}
   123  	}
   124  	// Check none exist parameters and assign it with default value.
   125  	if filter {
   126  		for k, v := range kvMap[0] {
   127  			if _, ok = m[k]; !ok {
   128  				m[k] = v
   129  			}
   130  		}
   131  	}
   132  	return m
   133  }
   134  
   135  // GetRequestMapStrStr retrieve and returns all parameters passed from the client and custom
   136  // params as map[string]string, no matter what HTTP method the client is using. The parameter
   137  // `kvMap` specifies the keys retrieving from client parameters, the associated values are the
   138  // default values if the client does not pass.
   139  func (r *Request) GetRequestMapStrStr(kvMap ...map[string]interface{}) map[string]string {
   140  	requestMap := r.GetRequestMap(kvMap...)
   141  	if len(requestMap) > 0 {
   142  		m := make(map[string]string, len(requestMap))
   143  		for k, v := range requestMap {
   144  			m[k] = gconv.String(v)
   145  		}
   146  		return m
   147  	}
   148  	return nil
   149  }
   150  
   151  // GetRequestMapStrVar retrieve and returns all parameters passed from the client and custom
   152  // params as map[string]*gvar.Var, no matter what HTTP method the client is using. The parameter
   153  // `kvMap` specifies the keys retrieving from client parameters, the associated values are the
   154  // default values if the client does not pass.
   155  func (r *Request) GetRequestMapStrVar(kvMap ...map[string]interface{}) map[string]*gvar.Var {
   156  	requestMap := r.GetRequestMap(kvMap...)
   157  	if len(requestMap) > 0 {
   158  		m := make(map[string]*gvar.Var, len(requestMap))
   159  		for k, v := range requestMap {
   160  			m[k] = gvar.New(v)
   161  		}
   162  		return m
   163  	}
   164  	return nil
   165  }
   166  
   167  // GetRequestStruct retrieves all parameters passed from the client and custom params no matter
   168  // what HTTP method the client is using, and converts them to give the struct object. Note that
   169  // the parameter `pointer` is a pointer to the struct object.
   170  // The optional parameter `mapping` is used to specify the key to attribute mapping.
   171  func (r *Request) GetRequestStruct(pointer interface{}, mapping ...map[string]string) error {
   172  	_, err := r.doGetRequestStruct(pointer, mapping...)
   173  	return err
   174  }
   175  
   176  func (r *Request) doGetRequestStruct(pointer interface{}, mapping ...map[string]string) (data map[string]interface{}, err error) {
   177  	data = r.GetRequestMap()
   178  	if data == nil {
   179  		data = map[string]interface{}{}
   180  	}
   181  	// Default struct values.
   182  	if err = r.mergeDefaultStructValue(data, pointer); err != nil {
   183  		return data, nil
   184  	}
   185  	// `in` Tag Struct values.
   186  	if err = r.mergeInTagStructValue(data, pointer); err != nil {
   187  		return data, nil
   188  	}
   189  
   190  	return data, gconv.Struct(data, pointer, mapping...)
   191  }
   192  
   193  // mergeDefaultStructValue merges the request parameters with default values from struct tag definition.
   194  func (r *Request) mergeDefaultStructValue(data map[string]interface{}, pointer interface{}) error {
   195  	fields := r.serveHandler.Handler.Info.ReqStructFields
   196  	if len(fields) > 0 {
   197  		var (
   198  			foundKey   string
   199  			foundValue interface{}
   200  		)
   201  		for _, field := range fields {
   202  			if tagValue := field.TagDefault(); tagValue != "" {
   203  				foundKey, foundValue = gutil.MapPossibleItemByKey(data, field.Name())
   204  				if foundKey == "" {
   205  					data[field.Name()] = tagValue
   206  				} else {
   207  					if empty.IsEmpty(foundValue) {
   208  						data[foundKey] = tagValue
   209  					}
   210  				}
   211  			}
   212  		}
   213  		return nil
   214  	}
   215  
   216  	// provide non strict routing
   217  	tagFields, err := gstructs.TagFields(pointer, defaultValueTags)
   218  	if err != nil {
   219  		return err
   220  	}
   221  	if len(tagFields) > 0 {
   222  		var (
   223  			foundKey   string
   224  			foundValue interface{}
   225  		)
   226  		for _, field := range tagFields {
   227  			foundKey, foundValue = gutil.MapPossibleItemByKey(data, field.Name())
   228  			if foundKey == "" {
   229  				data[field.Name()] = field.TagValue
   230  			} else {
   231  				if empty.IsEmpty(foundValue) {
   232  					data[foundKey] = field.TagValue
   233  				}
   234  			}
   235  		}
   236  	}
   237  
   238  	return nil
   239  }
   240  
   241  // mergeInTagStructValue merges the request parameters with header or cookie values from struct `in` tag definition.
   242  func (r *Request) mergeInTagStructValue(data map[string]interface{}, pointer interface{}) error {
   243  	fields := r.serveHandler.Handler.Info.ReqStructFields
   244  	if len(fields) > 0 {
   245  		var (
   246  			foundKey   string
   247  			foundValue interface{}
   248  			headerMap  = make(map[string]interface{})
   249  			cookieMap  = make(map[string]interface{})
   250  		)
   251  
   252  		for k, v := range r.Header {
   253  			if len(v) > 0 {
   254  				headerMap[k] = v[0]
   255  			}
   256  		}
   257  
   258  		for _, cookie := range r.Cookies() {
   259  			cookieMap[cookie.Name] = cookie.Value
   260  		}
   261  
   262  		for _, field := range fields {
   263  			if tagValue := field.TagIn(); tagValue != "" {
   264  				switch tagValue {
   265  				case goai.ParameterInHeader:
   266  					foundHeaderKey, foundHeaderValue := gutil.MapPossibleItemByKey(headerMap, field.TagPriorityName())
   267  					if foundHeaderKey != "" {
   268  						foundKey, foundValue = gutil.MapPossibleItemByKey(data, foundHeaderKey)
   269  						if foundKey == "" {
   270  							data[field.Name()] = foundHeaderValue
   271  						} else {
   272  							if empty.IsEmpty(foundValue) {
   273  								data[foundKey] = foundHeaderValue
   274  							}
   275  						}
   276  					}
   277  				case goai.ParameterInCookie:
   278  					foundCookieKey, foundCookieValue := gutil.MapPossibleItemByKey(cookieMap, field.TagPriorityName())
   279  					if foundCookieKey != "" {
   280  						foundKey, foundValue = gutil.MapPossibleItemByKey(data, foundCookieKey)
   281  						if foundKey == "" {
   282  							data[field.Name()] = foundCookieValue
   283  						} else {
   284  							if empty.IsEmpty(foundValue) {
   285  								data[foundKey] = foundCookieValue
   286  							}
   287  						}
   288  					}
   289  				}
   290  			}
   291  		}
   292  	}
   293  	return nil
   294  }