func (r *router) HttpMatch(path, method string) (*Node, error) {
	srvPath, subPath, err := r.splitPath(path)
	if err != nil {
		return nil, err
	}
	routes, err := r.loadRemoteRoutes(srvPath)
	if err != nil {
		return nil, err
	}
	if len(routes) == 0 || routes == nil {
		return nil, constant.ErrResourceNotFound
	}
	if paths := r.pathMatch(routes, subPath); len(paths) > 0 {
		if node := r.methodMatch(paths, method); node != nil {
			return node, nil
		} else {
			return nil, constant.ErrMethodNotAllowed
		}
	}
	return nil, constant.ErrResourceNotFound
}
Based on reqeust.path and method (e.g GET /gogox/v1/greeter/hello),
this method will download all relavent nodes from consul KV store
according to parsed key (/gogox/v1/greeter) and find matching service (/hello)
package router
import (
	"strings"
	"github.com/hashicorp/consul/api"
	"github.com/nzgogo/govalidator"
	"github.com/nzgogo/micro/codec"
	"github.com/nzgogo/micro/constant"
)
type Handler func(*codec.Message, string) *Error
type Error struct {
	StatusCode int
	Message    string
}
type Router interface {
	Init(opts ...Option) error
	Routes() []*Node
	Add(*Node)
	Dispatch(*codec.Message) (Handler, error)
	HttpMatch(string, string) (*Node, error)
	Register() error
	Deregister() error
}
type router struct {
	routes []*Node
	opts   Options
}
type Node struct {
	Method             string              `json:"Method,omitempty"`
	Path               string              `json:"Path,omitempty"`
	ID                 string              `json:"ID"`
	Handler            Handler             `json:"-"`
	ValidationRules    govalidator.MapData `json:"ValidationRules,omitempty"`
	ValidationMessages govalidator.MapData `json:"ValidationMessages,omitempty"`
}
func (r *router) Init(opts ...Option) error {
	for _, o := range opts {
		o(&r.opts)
	}
	if *r.opts.Client == (api.Client{}) {
		var err error
		r.opts.Client, err = api.NewClient(api.DefaultConfig())
		if err != nil {
			return err
		}
	}
	return nil
}
func (r *router) Routes() []*Node {
	return r.routes
}
func (r *router) Add(n *Node) {
	for _, route := range r.routes {
		if route.ID == n.ID {
			route = n
			return
		}
	}
	r.routes = append(r.routes, n)
}
func (r *router) Register() error {
	if len(r.routes) == 0 {
		return nil
	}
	if r.opts.Client == nil {
		return nil
	}
	publicRoutes := make([]*Node, 0)
	for _, v := range r.routes {
		if v.Method != "" {
			publicRoutes = append(publicRoutes, v)
		}
	}
	value, err := codec.Marshal(publicRoutes)
	if err != nil {
		return err
	}
	kv := r.opts.Client.KV()
	p := &api.KVPair{Key: r.opts.name, Value: value}
	if _, err := kv.Put(p, nil); err != nil {
		return err
	}
	return nil
}
func (r *router) Deregister() error {
	if len(r.routes) == 0 {
		return nil
	}
	kv := r.opts.Client.KV()
	if _, err := kv.DeleteTree(r.opts.name, nil); err != nil {
		return err
	}
	return nil
}