手把手帶你使用 go-kit(基礎篇)


手把手帶你使用 go-kit

go-kit 是什么

Go kit 是一個微服務工具包集合。利用它提供的額API和規范可以創建健壯、可維護性高的微服務體系

Go-kit的三層架構

1、Service 
這里就是我們的業務類、接口等相關信息存放

2、EndPoint
定義Request、Response格式,並可以使用裝飾器(閉包)包裝函數,以此來實現各個中間件嵌套

3、Transport
主要負責與HTTP、gRPC、thrift等相關邏輯

上面是 Go-kit 定義的架構模式 這里我們引入一個最簡單的Demo

// 項目結構
-| Server
----| server.go
-| EndPoint
----| endpoint.go
-| Transport
----| Transport.go
- main.go

1.首先我們先寫Server層業務類

// Server/server.go
package Server

import "fmt"

// server.go 實現業務

// IServer 用於定義業務方法的接口
type IServer interface {
	// 這里只需要關注我 IServer 對業務所需要的方法即可
	// 例如: 我這里要實現一個問候的方法 和一個 bye的方法 比較簡單 傳入一個名字 返回一個名字
	Hello(name string) string
	Bye(name string) string
}

// Server 用於實現上面定義的接口
type Server struct {
	// 根據業務需求填充結構體...
}

// 實現上方定義的業務方法

func (s Server) Hello(name string) string {
	return fmt.Sprintf("%s:Hello", name)
}

func (s Server) Bye(name string) string {
	return fmt.Sprintf("%s:Bye", name)
}

2.接下來我們實現EndPoint中的內容

// EndPoint/endpoint.go
package EndPoint

import (
	"Songzhibin/go-kit-demo/v0/Server"
	"context"
	"github.com/go-kit/kit/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"`
}

// 這里創建構造函數 hello方法的業務處理
// MakeServerEndPointHello 創建關於業務的構造函數
// 傳入 Server/server.go 定義的相關業務接口
// 返回 go-kit/endpoint.Endpoint (實際上就是一個函數簽名)
func MakeServerEndPointHello(s Server.IServer) endpoint.Endpoint {
	// 這里使用閉包,可以在這里做一些中間件業務的處理
	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
		// request 是在對應請求來時傳入的參數(這里的request 實際上是等下我們要將的Transport中一個decode函數中處理獲得的參數)
		// 這里進行以下斷言
		r, ok := request.(HelloRequest)
		if !ok {
			return Response{}, nil
		}
		// 這里實際上就是調用我們在Server/server.go中定義的業務邏輯
		// 我們拿到了 Request.Name 那么我們就可以調用我們的業務 Server.IServer 中的方法來處理這個數據並返回
		// 具體的業務邏輯具體定義....
		return HelloResponse{Reply: s.Hello(r.Name)}, nil
		// response 這里返回的response 可以返回任意的 不過根據規范是要返回我們剛才定義好的返回對象

	}
}

// 這里創建構造函數 Bye方法的業務處理
// MakeServerEndPointBye 創建關於業務的構造函數
// 傳入 Server/server.go 定義的相關業務接口
// 返回 go-kit/endpoint.Endpoint (實際上就是一個函數簽名)
func MakeServerEndPointBye(s Server.IServer) endpoint.Endpoint {
	// 這里使用閉包,可以在這里做一些中間件業務的處理
	return func(ctx context.Context, request interface{}) (response interface{}, err error) {
		// request 是在對應請求來時傳入的參數(這里的request 實際上是等下我們要將的Transport中一個decode函數中處理獲得的參數)
		// 這里進行以下斷言
		r, ok := request.(ByeRequest)
		if !ok {
			return Response{}, nil
		}
		// 這里實際上就是調用我們在Server/server.go中定義的業務邏輯
		// 我們拿到了 Request.Name 那么我們就可以調用我們的業務 Server.IServer 中的方法來處理這個數據並返回
		// 具體的業務邏輯具體定義....
		return ByeResponse{Reply: s.Bye(r.Name)}, nil
		// response 這里返回的response 可以返回任意的 不過根據規范是要返回我們剛才定義好的返回對象
	}
}

3.最后我們實現重中之重的 Transport

// Transport/transport.go
package Transport

import (
	"Songzhibin/go-kit-demo/v0/EndPoint"
	"context"
	"encoding/json"
	"errors"
	"net/http"
)

// Transport/transport.go 主要負責HTTP、gRpc、thrift等相關的邏輯

// 這里有兩個關鍵函數
// DecodeRequest & EncodeResponse 函數簽名是固定的喲
// func DecodeRequest(c context.Context, request *http.Request) (interface{}, error)
// func EncodeResponse(c context.Context, w http.ResponseWriter, response interface{}) error

// HelloDecodeRequest 解碼 后封裝至 EndPoint中定義的 Request格式中
func HelloDecodeRequest(c context.Context, request *http.Request) (interface{}, error) {
	// 這里主要就是通過 request 拿到對應的參數構造成在 EndPoint中定義的 Request結構體即可

	name := request.URL.Query().Get("name")
	if name == "" {
		return nil, errors.New("無效參數")
	}
	// 這里返回的是
	return EndPoint.HelloRequest{Name: name}, nil
}

// HelloEncodeResponse 通過響應封裝成 EndPoint中定義的 Response結構體即可
func HelloEncodeResponse(c context.Context, w http.ResponseWriter, response interface{}) error {
	// 這里將Response返回成有效的json格式給http

	// 設置請求頭信息
	w.Header().Set("Content-Type", "application/json;charset=utf-8")
	// 使用內置json包轉換
	return json.NewEncoder(w).Encode(response)
}

// ByeDecodeRequest 解碼 后封裝至 EndPoint中定義的 Request格式中
func ByeDecodeRequest(c context.Context, request *http.Request) (interface{}, error) {
	// 這里主要就是通過 request 拿到對應的參數構造成在 EndPoint中定義的 Request結構體即可

	name := request.URL.Query().Get("name")
	if name == "" {
		return nil, errors.New("無效參數")
	}
	// 這里返回的是
	return EndPoint.ByeRequest{Name: name}, nil
}

// sayEncodeResponse 通過響應封裝成 EndPoint中定義的 Response結構體即可
func sayEncodeResponse(c context.Context, w http.ResponseWriter, response interface{}) error {
	// 這里將Response返回成有效的json格式給http

	// 設置請求頭信息
	w.Header().Set("Content-Type", "application/json;charset=utf-8")
	// 使用內置json包轉換
	return json.NewEncoder(w).Encode(response)
}

4.服務啟動

// main.go
package main

import (
	EndPoint1 "Songzhibin/go-kit-demo/v0/EndPoint"
	"Songzhibin/go-kit-demo/v0/Server"
	"Songzhibin/go-kit-demo/v0/Transport"
	httpTransport "github.com/go-kit/kit/transport/http"
	"net/http"
)

// 服務發布

func main() {
	// 1.先創建我們最開始定義的Server/server.go
	s := Server.Server{}

	// 2.在用EndPoint/endpoint.go 創建業務服務
	hello := EndPoint1.MakeServerEndPointHello(s)
	Bye := EndPoint1.MakeServerEndPointBye(s)

	// 3.使用 kit 創建 handler
	// 固定格式
	// 傳入 業務服務 以及 定義的 加密解密方法
	helloServer := httpTransport.NewServer(hello, Transport.HelloDecodeRequest, Transport.HelloEncodeResponse)
	sayServer := httpTransport.NewServer(Bye, Transport.ByeDecodeRequest, Transport.ByeEncodeResponse)

	// 使用http包啟動服務
	go http.ListenAndServe("0.0.0.0:8000", helloServer)

	go http.ListenAndServe("0.0.0.0:8001", sayServer)
	select {}
}

我們嘗試運行一下


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM