zoukankan      html  css  js  c++  java
  • 手把手带你使用 go-kit(客户端直连)

    我们客户端的架构与服务的类似

    根据我们Demo的示例,我们创建一个客户端,客户端与服务端架构类似

    // 项目结构
    -| Client
    ----| Client.go
    -| EndPoint
    ----| endpoint.go
    -| Transport
    ----| Transport.go
    - main.go
    

    1.首先我们还是先写Client实例

    // Client/client.go
    package Client
    
    import (
    	"context"
    	"fmt"
    	"github.com/go-kit/kit/transport/http"
    	"net/url"
    	"strings"
    )
    
    // Direct: 直接调用服务端
    // method:方法 fullUrl: 完整的url http://localhost:8000
    // enc: http.EncodeRequestFunc dec: http.DecodeResponseFunc 这两个函数具体等一下会在Transport中进行详细解释
    // requestStruct: 根据EndPoint定义的request结构体传参
    func Direct(method string, fullUrl string, enc http.EncodeRequestFunc, dec http.DecodeResponseFunc, requestStruct interface{}) (interface{}, error) {
    	// 1.解析url
    	target, err := url.Parse(fullUrl)
    	if err != nil {
    		fmt.Println(err)
    		return nil, err
    	}
    	// kit调用服务端拿到Client对象
    	client := http.NewClient(strings.ToUpper(method), target, enc, dec)
    	// 调用服务 client.Endpoint()返回一个可执行函数 传入context 和 请求数据结构体
    	return client.Endpoint()(context.Background(), requestStruct)
    }
    

    2.EndPoint与之前没有变化,删除了一些逻辑

    // EndPoint/endpoint.go
    package EndPoint
    
    // endpoint.go 定义 Request、Response 格式, 并且可以使用闭包来实现各种中间件的嵌套
    // 这里了解 protobuf 的比较好理解点
    // 就是声明 接收数据和响应数据的结构体 并通过构造函数创建 在创建的过程当然可以使用闭包来进行一些你想要的操作啦
    
    // 这里根据我们Demo来创建一个响应和请求
    // 当然你想怎么创建怎么创建 也可以共用 这里我分开写 便于大家看的清楚
    
    // Hello 业务使用的请求和响应格式
    // HelloRequest 请求格式
    type HelloRequest struct {
    	Name string `json:"name"`
    }
    
    // HelloResponse 响应格式
    type HelloResponse struct {
    	Reply string `json:"reply"`
    }
    
    // Bye 业务使用的请求和响应格式
    // ByeRequest 请求格式
    type ByeRequest struct {
    	Name string `json:"name"`
    }
    
    // ByeResponse 响应格式
    type ByeResponse struct {
    	Reply string `json:"reply"`
    }
    
    // ------------ 当然 也可以通用的写 ----------
    // Request 请求格式
    type Request struct {
    	Name string `json:"name"`
    }
    
    // Response 响应格式
    type Response struct {
    	Reply string `json:"reply"`
    }
    

    3.修改Transport内容,逻辑与服务的正好相反

    // Transport/transport.go
    package Transport
    
    import (
    	"Songzhibin/go-kit-demo/v0client/EndPoint"
    	"context"
    	"encoding/json"
    	"errors"
    	"net/http"
    	"net/url"
    	"strconv"
    )
    
    // Transport/transport.go 主要负责HTTP、gRpc、thrift等相关的逻辑
    
    // 这里有两个关键函数
    // DecodeRequest & EncodeResponse 函数签名是固定的哟
    // func EncodeRequestFunc (context.Context, *http.Request, interface{}) error
    // func DecodeResponseFunc (context.Context, *http.Response) (response interface{}, err error)
    
    // HelloEncodeRequestFunc: 处理请求数据符合服务方要求的数据
    func HelloEncodeRequestFunc(c context.Context, request *http.Request, r interface{}) error {
    	// r就是我们在EndPoint中定义的请求响应对象
    	req, ok := r.(EndPoint.HelloRequest)
    	if !ok {
    		return errors.New("断言失败")
    	}
    	// 拿到自定义的请求对象对url做业务处理
    	request.URL.Path += "/hello"
    	data := url.Values{}
    	data.Set("name", req.Name)
    	request.URL.RawQuery = data.Encode()
    	// 实际上这里做的就是增加url参数 body之类的一些事情,简而言之就是构建http请求需要的一些资源
    	return nil
    }
    
    // HelloDecodeResponseFunc: 解密服务方传回的数据
    func HelloDecodeResponseFunc(c context.Context, res *http.Response) (response interface{}, err error) {
    	// 判断响应
    	if res.StatusCode != 200 {
    		return nil, errors.New("异常的响应码" + strconv.Itoa(res.StatusCode))
    	}
    	// body中的内容需要我们解析成我们通用定义好的内容
    	var r EndPoint.HelloResponse
    	err = json.NewDecoder(res.Body).Decode(&r)
    	if err != nil {
    		return nil, err
    	}
    	return r, nil
    }
    
    // ByeEncodeRequestFunc: 处理请求数据符合服务方要求的数据
    func ByeEncodeRequestFunc(c context.Context, request *http.Request, r interface{}) error {
    	// r就是我们在EndPoint中定义的请求响应对象
    	req, ok := r.(EndPoint.HelloRequest)
    	if !ok {
    		return errors.New("断言失败")
    	}
    	// 拿到自定义的请求对象对url做业务处理
    	request.URL.Path += "/bye"
    	data := url.Values{}
    	data.Set("name", req.Name)
    	request.URL.RawQuery = data.Encode()
    	// 实际上这里做的就是增加url参数 body之类的一些事情,简而言之就是构建http请求需要的一些资源
    	return nil
    }
    
    // ByeDecodeResponseFunc: 解密服务方传回的数据
    func ByeDecodeResponseFunc(c context.Context, res *http.Response) (response interface{}, err error) {
    	// 判断响应
    	if res.StatusCode != 200 {
    		return nil, errors.New("异常的响应码" + strconv.Itoa(res.StatusCode))
    	}
    	// body中的内容需要我们解析成我们通用定义好的内容
    	var r EndPoint.HelloResponse
    	err = json.NewDecoder(res.Body).Decode(&r)
    	if err != nil {
    		return nil, err
    	}
    	return r, nil
    }
    

    直接调用

    // main.go
    package main
    
    import (
    	"Songzhibin/go-kit-demo/v0client/Client"
    	"Songzhibin/go-kit-demo/v0client/EndPoint"
    	"Songzhibin/go-kit-demo/v0client/Transport"
    	"fmt"
    )
    
    // 调用我们在client封装的函数就好了
    func main() {
    	i, err := Client.Direct("GET", "http://127.0.0.1:8000", Transport.HelloEncodeRequestFunc, Transport.HelloDecodeResponseFunc, EndPoint.HelloRequest{Name: "songzhibin"})
    	if err != nil {
    		fmt.Println(err)
    		return
    	}
    	res, ok := i.(EndPoint.HelloResponse)
    	if !ok {
    		fmt.Println("no ok")
    		return
    	}
    	fmt.Println(res)
    }
    
    Songzhibin
  • 相关阅读:
    maven下载出错
    Android中TextView和EditView常用属性设置
    在python3.6环境下使用cxfreeze打包程序
    Python安装环境配置和多版本共存
    python manage.py migrate出错
    python使用pip安装模块出错 Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None))
    类的继承
    显示一张大图两张小图思路!banner数据库设计
    微信模板
    微擎小程序第二次请求 promise
  • 原文地址:https://www.cnblogs.com/binHome/p/13936129.html
Copyright © 2011-2022 走看看