package util
import (
"context"
"go.etcd.io/etcd/clientv3"
"io/ioutil"
"net/http"
"regexp"
"time"
)
type Client struct {
client *clientv3.Client
Services []*ServiceInfo
}
type ServiceInfo struct {
ServiceID string
ServiceName string
ServiceAddr string
}
func NewClient() *Client {
config := clientv3.Config{
Endpoints: []string{"106.12.72.181:23791", "106.12.72.181:23792"},
DialTimeout: 10 * time.Second,
}
client, _ := clientv3.New(config)
return &Client{client: client}
}
func (this *Client) LoadService() error {
kv := clientv3.NewKV(this.client)
res, err := kv.Get(context.TODO(), "/services", clientv3.WithPrefix())
if err != nil {
return err
}
for _, item := range res.Kvs {
this.parseService(item.Key, item.Value)
}
return nil
}
func (this *Client) parseService(key []byte, value []byte) {
reg := regexp.MustCompile("/services/(\\w+)/(\\w+)")
if reg.Match(key) {
idandname := reg.FindSubmatch(key)
sid := idandname[1]
sname := idandname[2]
this.Services = append(this.Services, &ServiceInfo{ServiceID: string(sid),
ServiceName: string(sname), ServiceAddr: string(value)})
}
}
//定义一个高阶函数返回处理具体url的函数
func (this *Client) GetService(sname string, method string, encodeFunc EncodeRequestFunc) Endpoint {
for _, service := range this.Services {
if service.ServiceName == sname {
return func(ctx context.Context, requestParam interface{}) (responseResult interface{}, err error) {
httpClient := &http.Client{}
httpRequest, err := http.NewRequest(method, "http://"+service.ServiceAddr, nil)
if err != nil {
return nil, err
}
err = encodeFunc(ctx, httpRequest, requestParam) //这一步是关键,将httpRequest的url修改了
if err != nil {
return nil, err
}
res, err := httpClient.Do(httpRequest)
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return err, nil
}
return string(body), nil
}
}
}
return func(ctx context.Context, requestParam interface{}) (responseResult interface{}, err error) {
return nil, err
}
}
各个url处理的函数类型申明
package util
import (
"context"
"net/http"
)
//request是调用参数,response是返回结果
type Endpoint func(ctx context.Context,requestParam interface{})(responseResult interface{},err error)
//决定请求path以及参数
type EncodeRequestFunc func(context.Context,*http.Request,interface{}) error
各个url处理的函数类型实现
package serivces
import (
"context"
"net/http"
"strconv"
)
func ProdEncodeFunc(ctx context.Context,httpRequest *http.Request, requestParams interface{}) error {
prodr:=requestParams.(ProdRequest)
httpRequest.URL.Path+="/product/"+strconv.Itoa(prodr.ProdId)
return nil
}
怎么调用这些函数
package main
import (
"context"
"fmt"
"goetcd/services"
"goetcd/util"
"log"
)
func main() {
client:=util.NewClient()
err:=client.LoadService()
if err!=nil{
log.Fatal(err)
}
endpoint:=client.GetService("productservice","GET", serivces.ProdEncodeFunc)
res,err:= endpoint(context.Background(),serivces.ProdRequest{ProdId:106})
if err!=nil{
log.Fatal(err)
}
fmt.Println(res)
}