func (c URL) ToMap() map[string]string {
	paramsMap := make(map[string]string)
	c.RangeParams(func(key, value string) bool {
		paramsMap[key] = value
		return true
	})
	if c.Protocol != "" {
		paramsMap["protocol"] = c.Protocol
	}
	if c.Username != "" {
		paramsMap["username"] = c.Username
	}
	if c.Password != "" {
		paramsMap["password"] = c.Password
	}
	if c.Location != "" {
		paramsMap["host"] = strings.Split(c.Location, ":")[0]
		var port string
		if strings.Contains(c.Location, ":") {
			port = strings.Split(c.Location, ":")[1]
		} else {
			port = "0"
		}
		paramsMap["port"] = port
	}
	if c.Protocol != "" {
		paramsMap["protocol"] = c.Protocol
	}
	if c.Path != "" {
		paramsMap["path"] = c.Path
	}
	if len(paramsMap) == 0 {
		return nil
	}
	return paramsMap
}
ToMap transfer URL to Map
package common
import (
	"bytes"
	"encoding/base64"
	"fmt"
	"math"
	"net"
	"net/url"
	"strconv"
	"strings"
	"sync"
	gxset "github.com/dubbogo/gost/container/set"
	"github.com/jinzhu/copier"
	"mosn.io/pkg/registry/dubbo/common/constant"
	perrors "github.com/pkg/errors"
	uuid "github.com/satori/go.uuid"
)
const (
	CONSUMER = iota
	CONFIGURATOR
	ROUTER
	PROVIDER
)
var (
	DubboNodes = [...]string{"consumers", "configurators", "routers", "providers"}
	DubboRole = [...]string{"consumer", "", "routers", "provider"}
)
type RoleType int
func (t RoleType) String() string {
	return DubboNodes[t]
}
func (t RoleType) Role() string {
	return DubboRole[t]
}
type baseUrl struct {
	Protocol string
	Location string  
	Ip       string
	Port     string
	paramsLock   sync.RWMutex
	params       url.Values
	PrimitiveURL string
}
type URL struct {
	baseUrl
	Path     string  
	Username string
	Password string
	Methods  []string
	SubURL *URL
}
type option func(*URL)
func WithUsername(username string) option {
	return func(url *URL) {
		url.Username = username
	}
}
func WithPassword(pwd string) option {
	return func(url *URL) {
		url.Password = pwd
	}
}
func WithMethods(methods []string) option {
	return func(url *URL) {
		url.Methods = methods
	}
}
func WithParams(params url.Values) option {
	return func(url *URL) {
		url.params = params
	}
}
func WithParamsValue(key, val string) option {
	return func(url *URL) {
		url.SetParam(key, val)
	}
}
func WithProtocol(proto string) option {
	return func(url *URL) {
		url.Protocol = proto
	}
}
func WithIp(ip string) option {
	return func(url *URL) {
		url.Ip = ip
	}
}
func WithPort(port string) option {
	return func(url *URL) {
		url.Port = port
	}
}
func WithPath(path string) option {
	return func(url *URL) {
		url.Path = "/" + strings.TrimPrefix(path, "/")
	}
}
func WithLocation(location string) option {
	return func(url *URL) {
		url.Location = location
	}
}
func WithToken(token string) option {
	return func(url *URL) {
		if len(token) > 0 {
			value := token
			if strings.ToLower(token) == "true" || strings.ToLower(token) == "default" {
				value = uuid.NewV4().String()
			}
			url.SetParam(constant.TOKEN_KEY, value)
		}
	}
}
func NewURLWithOptions(opts ...option) *URL {
	url := &URL{}
	for _, opt := range opts {
		opt(url)
	}
	url.Location = url.Ip + ":" + url.Port
	return url
}
func NewURL(urlString string, opts ...option) (URL, error) {
	var (
		err          error
		rawUrlString string
		serviceUrl   *url.URL
		s            = URL{baseUrl: baseUrl{}}
	)
	if urlString == "" {
		return s, nil
	}
	rawUrlString, err = url.QueryUnescape(urlString)
	if err != nil {
		return s, perrors.Errorf("url.QueryUnescape(%s),  error{%v}", urlString, err)
	}
	if strings.Index(rawUrlString, "//") < 0 {
		t := URL{baseUrl: baseUrl{}}
		for _, opt := range opts {
			opt(&t)
		}
		rawUrlString = t.Protocol + "://" + rawUrlString
	}
	serviceUrl, err = url.Parse(rawUrlString)
	if err != nil {
		return s, perrors.Errorf("url.Parse(url string{%s}),  error{%v}", rawUrlString, err)
	}
	s.params, err = url.ParseQuery(serviceUrl.RawQuery)
	if err != nil {
		return s, perrors.Errorf("url.ParseQuery(raw url string{%s}),  error{%v}", serviceUrl.RawQuery, err)
	}
	s.PrimitiveURL = urlString
	s.Protocol = serviceUrl.Scheme
	s.Username = serviceUrl.User.Username()
	s.Password, _ = serviceUrl.User.Password()
	s.Location = serviceUrl.Host
	s.Path = serviceUrl.Path
	if strings.Contains(s.Location, ":") {
		s.Ip, s.Port, err = net.SplitHostPort(s.Location)
		if err != nil {
			return s, perrors.Errorf("net.SplitHostPort(url.Host{%s}), error{%v}", s.Location, err)
		}
	}
	for _, opt := range opts {
		opt(&s)
	}
	return s, nil
}
func (c URL) URLEqual(url URL) bool {
	c.Ip = ""
	c.Port = ""
	url.Ip = ""
	url.Port = ""
	cGroup := c.GetParam(constant.GROUP_KEY, "")
	urlGroup := url.GetParam(constant.GROUP_KEY, "")
	cKey := c.Key()
	urlKey := url.Key()
	if cGroup == constant.ANY_VALUE {
		cKey = strings.Replace(cKey, "group=*", "group="+urlGroup, 1)
	} else if urlGroup == constant.ANY_VALUE {
		urlKey = strings.Replace(urlKey, "group=*", "group="+cGroup, 1)
	}
	if cKey != urlKey {
		return false
	}
	if url.GetParam(constant.ENABLED_KEY, "true") != "true" && url.GetParam(constant.ENABLED_KEY, "") != constant.ANY_VALUE {
		return false
	}
	if !isMatchCategory(url.GetParam(constant.CATEGORY_KEY, constant.DEFAULT_CATEGORY), c.GetParam(constant.CATEGORY_KEY, constant.DEFAULT_CATEGORY)) {
		return false
	}
	return true
}
func isMatchCategory(category1 string, category2 string) bool {
	if len(category2) == 0 {
		return category1 == constant.DEFAULT_CATEGORY
	} else if strings.Contains(category2, constant.ANY_VALUE) {
		return true
	} else if strings.Contains(category2, constant.REMOVE_VALUE_PREFIX) {
		return !strings.Contains(category2, constant.REMOVE_VALUE_PREFIX+category1)
	} else {
		return strings.Contains(category2, category1)
	}
}
func (c URL) String() string {
	var buildString string
	if len(c.Username) == 0 && len(c.Password) == 0 {
		buildString = fmt.Sprintf(
			"%s://%s:%s%s?",
			c.Protocol, c.Ip, c.Port, c.Path)
	} else {
		buildString = fmt.Sprintf(
			"%s://%s:%s@%s:%s%s?",
			c.Protocol, c.Username, c.Password, c.Ip, c.Port, c.Path)
	}
	c.paramsLock.RLock()
	buildString += c.params.Encode()
	c.paramsLock.RUnlock()
	return buildString
}
func (c URL) Key() string {
	buildString := fmt.Sprintf(
		"%s://%s:%s@%s:%s/?interface=%s&group=%s&version=%s",
		c.Protocol, c.Username, c.Password, c.Ip, c.Port, c.Service(), c.GetParam(constant.GROUP_KEY, ""), c.GetParam(constant.VERSION_KEY, ""))
	return buildString
}
func (c URL) ServiceKey() string {
	intf := c.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/"))
	if intf == "" {
		return ""
	}
	buf := &bytes.Buffer{}
	group := c.GetParam(constant.GROUP_KEY, "")
	if group != "" {
		buf.WriteString(group)
		buf.WriteString("/")
	}
	buf.WriteString(intf)
	version := c.GetParam(constant.VERSION_KEY, "")
	if version != "" && version != "0.0.0" {
		buf.WriteString(":")
		buf.WriteString(version)
	}
	return buf.String()
}
func (c *URL) ColonSeparatedKey() string {
	intf := c.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/"))
	if intf == "" {
		return ""
	}
	buf := &bytes.Buffer{}
	buf.WriteString(intf)
	buf.WriteString(":")
	version := c.GetParam(constant.VERSION_KEY, "")
	if version != "" && version != "0.0.0" {
		buf.WriteString(version)
	}
	group := c.GetParam(constant.GROUP_KEY, "")
	buf.WriteString(":")
	if group != "" {
		buf.WriteString(group)
	}
	return buf.String()
}
func (c *URL) EncodedServiceKey() string {
	serviceKey := c.ServiceKey()
	return strings.Replace(serviceKey, "/", "*", 1)
}
func (c URL) Service() string {
	service := c.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/"))
	if service != "" {
		return service
	} else if c.SubURL != nil {
		service = c.GetParam(constant.INTERFACE_KEY, strings.TrimPrefix(c.Path, "/"))
		if service != "" {  
			return service
		}
	}
	return ""
}
func (c *URL) AddParam(key string, value string) {
	c.paramsLock.Lock()
	c.params.Add(key, value)
	c.paramsLock.Unlock()
}
func (c *URL) SetParam(key string, value string) {
	c.paramsLock.Lock()
	c.params.Set(key, value)
	c.paramsLock.Unlock()
}
func (c *URL) RangeParams(f func(key, value string) bool) {
	c.paramsLock.RLock()
	defer c.paramsLock.RUnlock()
	for k, v := range c.params {
		if !f(k, v[0]) {
			break
		}
	}
}
func (c URL) GetParam(s string, d string) string {
	var r string
	c.paramsLock.RLock()
	if r = c.params.Get(s); len(r) == 0 {
		r = d
	}
	c.paramsLock.RUnlock()
	return r
}
func (c URL) GetParams() url.Values {
	return c.params
}
func (c URL) GetParamAndDecoded(key string) (string, error) {
	c.paramsLock.RLock()
	defer c.paramsLock.RUnlock()
	ruleDec, err := base64.URLEncoding.DecodeString(c.GetParam(key, ""))
	value := string(ruleDec)
	return value, err
}
func (c URL) GetRawParam(key string) string {
	switch key {
	case "protocol":
		return c.Protocol
	case "username":
		return c.Username
	case "host":
		return strings.Split(c.Location, ":")[0]
	case "password":
		return c.Password
	case "port":
		return c.Port
	case "path":
		return c.Path
	default:
		return c.GetParam(key, "")
	}
}
func (c URL) GetParamBool(s string, d bool) bool {
	var r bool
	var err error
	if r, err = strconv.ParseBool(c.GetParam(s, "")); err != nil {
		return d
	}
	return r
}
func (c URL) GetParamInt(s string, d int64) int64 {
	var r int
	var err error
	if r, err = strconv.Atoi(c.GetParam(s, "")); r == 0 || err != nil {
		return d
	}
	return int64(r)
}
func (c URL) GetMethodParamInt(method string, key string, d int64) int64 {
	var r int
	var err error
	c.paramsLock.RLock()
	defer c.paramsLock.RUnlock()
	if r, err = strconv.Atoi(c.GetParam("methods."+method+"."+key, "")); r == 0 || err != nil {
		return d
	}
	return int64(r)
}
func (c URL) GetMethodParamInt64(method string, key string, d int64) int64 {
	r := c.GetMethodParamInt(method, key, math.MinInt64)
	if r == math.MinInt64 {
		return c.GetParamInt(key, d)
	}
	return r
}
func (c URL) GetMethodParam(method string, key string, d string) string {
	var r string
	if r = c.GetParam("methods."+method+"."+key, ""); r == "" {
		r = d
	}
	return r
}
func (c URL) GetMethodParamBool(method string, key string, d bool) bool {
	r := c.GetParamBool("methods."+method+"."+key, d)
	return r
}
func (c *URL) RemoveParams(set *gxset.HashSet) {
	c.paramsLock.Lock()
	defer c.paramsLock.Unlock()
	for k := range set.Items {
		s := k.(string)
		delete(c.params, s)
	}
}
func (c *URL) SetParams(m url.Values) {
	for k := range m {
		c.SetParam(k, m.Get(k))
	}
}