当前位置: 首页 > 工具软件 > go-bm > 使用案例 >

聊聊dubbo-go-proxy的ParamMapper

杨建章
2023-12-01

本文主要研究一下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

 类似资料: