序
本文次要钻研一下 dubbo-go-proxy 的 ParamMapper
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 办法
headerMapper
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
uriMapper
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
queryStringsMapper
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
bodyMapper
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 参数
mapPrepare
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
setTarget
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 的对应局部。
doc
- dubbo-go-proxy