本文次要钻研一下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{}// nolintfunc (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{}// nolintfunc (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{}// nolintfunc (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