本文主要研究一下dubbo-go-proxy的ParamMapper
dubbo-go-proxy/pkg/client/mapper.go
// ParamMapper defines the interface about how to map the params in the inbound request. type ParamMapper interface { // Map implements how the request parameters map to the target parameters described by config.MappingParam Map(config.MappingParam, *Request, interface{}, RequestOption) error }
ParamMapper接口定义了Map方法
dubbo-go-proxy/pkg/client/http/mapper.go
type headerMapper struct{} // nolint func (hm headerMapper) Map(mp config.MappingParam, c *client.Request, rawTarget interface{}, option client.RequestOption) error { target, fromKey, to, toKey, err := mapPrepare(mp, rawTarget) if err != nil { return err } rawHeader := c.IngressRequest.Header.Get(fromKey[0]) if len(rawHeader) == 0 { return errors.Errorf("Header %s not found", fromKey[0]) } setTarget(target, to, toKey[0], rawHeader) return nil }
headerMapper实现了ParamMapper接口,其Map方法提取和映射header
dubbo-go-proxy/pkg/client/http/mapper.go
type uriMapper struct{} func (um uriMapper) Map(mp config.MappingParam, c *client.Request, rawTarget interface{}, option client.RequestOption) error { target, fromKey, to, toKey, err := mapPrepare(mp, rawTarget) if err != nil { return err } if to == constant.RequestURI { } uriValues := router.GetURIParams(&c.API, *c.IngressRequest.URL) if uriValues == nil { return errors.New("No URI parameters found") } setTarget(target, to, strings.Join(toKey, constant.Dot), uriValues.Get(fromKey[0])) return nil }
uriMapper实现了ParamMapper接口,其Map方法用于提取和映射uri
dubbo-go-proxy/pkg/client/http/mapper.go
type queryStringsMapper struct{} // nolint func (qs queryStringsMapper) Map(mp config.MappingParam, c *client.Request, rawTarget interface{}, option client.RequestOption) error { target, fromKey, to, toKey, err := mapPrepare(mp, rawTarget) if err != nil { return err } queryValues, err := url.ParseQuery(c.IngressRequest.URL.RawQuery) if err != nil { return errors.Wrap(err, "Error happened when parsing the query paramters") } rawValue := queryValues.Get(fromKey[0]) if len(rawValue) == 0 { return errors.Errorf("%s in query parameters not found", fromKey[0]) } setTarget(target, to, toKey[0], rawValue) return nil }
queryStringsMapper实现了ParamMapper接口,其Map方法用于提取和映射query string
dubbo-go-proxy/pkg/client/http/mapper.go
type bodyMapper struct{} // nolint func (bm bodyMapper) Map(mp config.MappingParam, c *client.Request, rawTarget interface{}, option client.RequestOption) error { // TO-DO: add support for content-type other than application/json target, fromKey, to, toKey, err := mapPrepare(mp, rawTarget) if err != nil { return err } rawBody, err := ioutil.ReadAll(c.IngressRequest.Body) defer func() { c.IngressRequest.Body = ioutil.NopCloser(bytes.NewReader(rawBody)) }() if err != nil { return err } mapBody := map[string]interface{}{} json.Unmarshal(rawBody, &mapBody) val, err := client.GetMapValue(mapBody, fromKey) if err != nil { return errors.Wrapf(err, "Error when get body value from key %s", fromKey) } setTarget(target, to, strings.Join(toKey, constant.Dot), val) return nil }
bodyMapper实现了ParamMapper接口,其Map方法用于提取和映射body参数
dubbo-go-proxy/pkg/client/http/mapper.go
func mapPrepare(mp config.MappingParam, rawTarget interface{}) (target *requestParams, fromKey []string, to string, toKey []string, err error) { // ensure the target is a pointer and type is requestParams target, err = validateTarget(rawTarget) if err != nil { return nil, nil, "", nil, err } // retrieve the mapping values' origin param name _, fromKey, err = client.ParseMapSource(mp.Name) if err != nil { return nil, nil, "", nil, err } // retrieve the mapping values' target param name and param types(header/uri/query/request body) to, toKey, err = client.ParseMapSource(mp.MapTo) if err != nil { return nil, nil, "", nil, err } return target, fromKey, to, toKey, nil }
mapPrepare方法根据config.MappingParam从rawTarget提取requestParams、fromKey、to、toKey
dubbo-go-proxy/pkg/client/http/mapper.go
func setTarget(target *requestParams, to string, key string, val interface{}) error { valType := reflect.TypeOf(val) if (to == constant.Headers || to == constant.QueryStrings) && valType.Kind() != reflect.String { return errors.Errorf("%s only accepts string", to) } switch to { case constant.Headers: target.Header.Set(key, val.(string)) case constant.RequestURI: target.URIParams.Set(key, val.(string)) case constant.QueryStrings: target.Query.Set(key, val.(string)) case constant.RequestBody: rawBody, err := ioutil.ReadAll(target.Body) defer func() { target.Body = ioutil.NopCloser(bytes.NewReader(rawBody)) }() if err != nil { return errors.New("Raw body parse failed") } mapBody := map[string]interface{}{} json.Unmarshal(rawBody, &mapBody) setMapWithPath(mapBody, key, val) rawBody, err = json.Marshal(mapBody) if err != nil { return errors.New("Stringify map to body failed") } default: return errors.Errorf("Mapping target to %s does not support", to) } return nil }
setTarget方法用于将val写入到requestParams的对应部分
dubbo-go-proxy的ParamMapper接口定义了Map方法;它有四个实现类分别是headerMapper、uriMapper、queryStringsMapper、bodyMapper;mapPrepare方法用于提取参数,setTarget方法用于将val写入到requestParams的对应部分。