手把手带你使用 go-kit(基础篇)
生活随笔
收集整理的這篇文章主要介紹了
手把手带你使用 go-kit(基础篇)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
手把手帶你使用 go-kit
go-kit 是什么
Go kit 是一個(gè)微服務(wù)工具包集合。利用它提供的額API和規(guī)范可以創(chuàng)建健壯、可維護(hù)性高的微服務(wù)體系
Go-kit的三層架構(gòu)
1、Service
這里就是我們的業(yè)務(wù)類、接口等相關(guān)信息存放
2、EndPoint
定義Request、Response格式,并可以使用裝飾器(閉包)包裝函數(shù),以此來(lái)實(shí)現(xiàn)各個(gè)中間件嵌套
3、Transport
主要負(fù)責(zé)與HTTP、gRPC、thrift等相關(guān)邏輯
上面是 Go-kit 定義的架構(gòu)模式 這里我們引入一個(gè)最簡(jiǎn)單的Demo
// 項(xiàng)目結(jié)構(gòu)
-| Server
----| server.go
-| EndPoint
----| endpoint.go
-| Transport
----| Transport.go
- main.go
1.首先我們先寫(xiě)Server層業(yè)務(wù)類
// Server/server.go
package Server
import "fmt"
// server.go 實(shí)現(xiàn)業(yè)務(wù)
// IServer 用于定義業(yè)務(wù)方法的接口
type IServer interface {
// 這里只需要關(guān)注我 IServer 對(duì)業(yè)務(wù)所需要的方法即可
// 例如: 我這里要實(shí)現(xiàn)一個(gè)問(wèn)候的方法 和一個(gè) bye的方法 比較簡(jiǎn)單 傳入一個(gè)名字 返回一個(gè)名字
Hello(name string) string
Bye(name string) string
}
// Server 用于實(shí)現(xiàn)上面定義的接口
type Server struct {
// 根據(jù)業(yè)務(wù)需求填充結(jié)構(gòu)體...
}
// 實(shí)現(xiàn)上方定義的業(yè)務(wù)方法
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.接下來(lái)我們實(shí)現(xiàn)EndPoint中的內(nèi)容
// EndPoint/endpoint.go
package EndPoint
import (
"Songzhibin/go-kit-demo/v0/Server"
"context"
"github.com/go-kit/kit/endpoint"
)
// endpoint.go 定義 Request、Response 格式, 并且可以使用閉包來(lái)實(shí)現(xiàn)各種中間件的嵌套
// 這里了解 protobuf 的比較好理解點(diǎn)
// 就是聲明 接收數(shù)據(jù)和響應(yīng)數(shù)據(jù)的結(jié)構(gòu)體 并通過(guò)構(gòu)造函數(shù)創(chuàng)建 在創(chuàng)建的過(guò)程當(dāng)然可以使用閉包來(lái)進(jìn)行一些你想要的操作啦
// 這里根據(jù)我們Demo來(lái)創(chuàng)建一個(gè)響應(yīng)和請(qǐng)求
// 當(dāng)然你想怎么創(chuàng)建怎么創(chuàng)建 也可以共用 這里我分開(kāi)寫(xiě) 便于大家看的清楚
// Hello 業(yè)務(wù)使用的請(qǐng)求和響應(yīng)格式
// HelloRequest 請(qǐng)求格式
type HelloRequest struct {
Name string `json:"name"`
}
// HelloResponse 響應(yīng)格式
type HelloResponse struct {
Reply string `json:"reply"`
}
// Bye 業(yè)務(wù)使用的請(qǐng)求和響應(yīng)格式
// ByeRequest 請(qǐng)求格式
type ByeRequest struct {
Name string `json:"name"`
}
// ByeResponse 響應(yīng)格式
type ByeResponse struct {
Reply string `json:"reply"`
}
// ------------ 當(dāng)然 也可以通用的寫(xiě) ----------
// Request 請(qǐng)求格式
type Request struct {
Name string `json:"name"`
}
// Response 響應(yīng)格式
type Response struct {
Reply string `json:"reply"`
}
// 這里創(chuàng)建構(gòu)造函數(shù) hello方法的業(yè)務(wù)處理
// MakeServerEndPointHello 創(chuàng)建關(guān)于業(yè)務(wù)的構(gòu)造函數(shù)
// 傳入 Server/server.go 定義的相關(guān)業(yè)務(wù)接口
// 返回 go-kit/endpoint.Endpoint (實(shí)際上就是一個(gè)函數(shù)簽名)
func MakeServerEndPointHello(s Server.IServer) endpoint.Endpoint {
// 這里使用閉包,可以在這里做一些中間件業(yè)務(wù)的處理
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
// request 是在對(duì)應(yīng)請(qǐng)求來(lái)時(shí)傳入的參數(shù)(這里的request 實(shí)際上是等下我們要將的Transport中一個(gè)decode函數(shù)中處理獲得的參數(shù))
// 這里進(jìn)行以下斷言
r, ok := request.(HelloRequest)
if !ok {
return Response{}, nil
}
// 這里實(shí)際上就是調(diào)用我們?cè)赟erver/server.go中定義的業(yè)務(wù)邏輯
// 我們拿到了 Request.Name 那么我們就可以調(diào)用我們的業(yè)務(wù) Server.IServer 中的方法來(lái)處理這個(gè)數(shù)據(jù)并返回
// 具體的業(yè)務(wù)邏輯具體定義....
return HelloResponse{Reply: s.Hello(r.Name)}, nil
// response 這里返回的response 可以返回任意的 不過(guò)根據(jù)規(guī)范是要返回我們剛才定義好的返回對(duì)象
}
}
// 這里創(chuàng)建構(gòu)造函數(shù) Bye方法的業(yè)務(wù)處理
// MakeServerEndPointBye 創(chuàng)建關(guān)于業(yè)務(wù)的構(gòu)造函數(shù)
// 傳入 Server/server.go 定義的相關(guān)業(yè)務(wù)接口
// 返回 go-kit/endpoint.Endpoint (實(shí)際上就是一個(gè)函數(shù)簽名)
func MakeServerEndPointBye(s Server.IServer) endpoint.Endpoint {
// 這里使用閉包,可以在這里做一些中間件業(yè)務(wù)的處理
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
// request 是在對(duì)應(yīng)請(qǐng)求來(lái)時(shí)傳入的參數(shù)(這里的request 實(shí)際上是等下我們要將的Transport中一個(gè)decode函數(shù)中處理獲得的參數(shù))
// 這里進(jìn)行以下斷言
r, ok := request.(ByeRequest)
if !ok {
return Response{}, nil
}
// 這里實(shí)際上就是調(diào)用我們?cè)赟erver/server.go中定義的業(yè)務(wù)邏輯
// 我們拿到了 Request.Name 那么我們就可以調(diào)用我們的業(yè)務(wù) Server.IServer 中的方法來(lái)處理這個(gè)數(shù)據(jù)并返回
// 具體的業(yè)務(wù)邏輯具體定義....
return ByeResponse{Reply: s.Bye(r.Name)}, nil
// response 這里返回的response 可以返回任意的 不過(guò)根據(jù)規(guī)范是要返回我們剛才定義好的返回對(duì)象
}
}
3.最后我們實(shí)現(xiàn)重中之重的 Transport
// Transport/transport.go
package Transport
import (
"Songzhibin/go-kit-demo/v0/EndPoint"
"context"
"encoding/json"
"errors"
"net/http"
)
// Transport/transport.go 主要負(fù)責(zé)HTTP、gRpc、thrift等相關(guān)的邏輯
// 這里有兩個(gè)關(guān)鍵函數(shù)
// DecodeRequest & EncodeResponse 函數(shù)簽名是固定的喲
// 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) {
// 這里主要就是通過(guò) request 拿到對(duì)應(yīng)的參數(shù)構(gòu)造成在 EndPoint中定義的 Request結(jié)構(gòu)體即可
name := request.URL.Query().Get("name")
if name == "" {
return nil, errors.New("無(wú)效參數(shù)")
}
// 這里返回的是
return EndPoint.HelloRequest{Name: name}, nil
}
// HelloEncodeResponse 通過(guò)響應(yīng)封裝成 EndPoint中定義的 Response結(jié)構(gòu)體即可
func HelloEncodeResponse(c context.Context, w http.ResponseWriter, response interface{}) error {
// 這里將Response返回成有效的json格式給http
// 設(shè)置請(qǐng)求頭信息
w.Header().Set("Content-Type", "application/json;charset=utf-8")
// 使用內(nèi)置json包轉(zhuǎn)換
return json.NewEncoder(w).Encode(response)
}
// ByeDecodeRequest 解碼 后封裝至 EndPoint中定義的 Request格式中
func ByeDecodeRequest(c context.Context, request *http.Request) (interface{}, error) {
// 這里主要就是通過(guò) request 拿到對(duì)應(yīng)的參數(shù)構(gòu)造成在 EndPoint中定義的 Request結(jié)構(gòu)體即可
name := request.URL.Query().Get("name")
if name == "" {
return nil, errors.New("無(wú)效參數(shù)")
}
// 這里返回的是
return EndPoint.ByeRequest{Name: name}, nil
}
// sayEncodeResponse 通過(guò)響應(yīng)封裝成 EndPoint中定義的 Response結(jié)構(gòu)體即可
func sayEncodeResponse(c context.Context, w http.ResponseWriter, response interface{}) error {
// 這里將Response返回成有效的json格式給http
// 設(shè)置請(qǐng)求頭信息
w.Header().Set("Content-Type", "application/json;charset=utf-8")
// 使用內(nèi)置json包轉(zhuǎn)換
return json.NewEncoder(w).Encode(response)
}
4.服務(wù)啟動(dòng)
// 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"
)
// 服務(wù)發(fā)布
func main() {
// 1.先創(chuàng)建我們最開(kāi)始定義的Server/server.go
s := Server.Server{}
// 2.在用EndPoint/endpoint.go 創(chuàng)建業(yè)務(wù)服務(wù)
hello := EndPoint1.MakeServerEndPointHello(s)
Bye := EndPoint1.MakeServerEndPointBye(s)
// 3.使用 kit 創(chuàng)建 handler
// 固定格式
// 傳入 業(yè)務(wù)服務(wù) 以及 定義的 加密解密方法
helloServer := httpTransport.NewServer(hello, Transport.HelloDecodeRequest, Transport.HelloEncodeResponse)
sayServer := httpTransport.NewServer(Bye, Transport.ByeDecodeRequest, Transport.ByeEncodeResponse)
// 使用http包啟動(dòng)服務(wù)
go http.ListenAndServe("0.0.0.0:8000", helloServer)
go http.ListenAndServe("0.0.0.0:8001", sayServer)
select {}
}
我們嘗試運(yùn)行一下
Songzhibin
總結(jié)
以上是生活随笔為你收集整理的手把手带你使用 go-kit(基础篇)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: matlab之reshape函数
- 下一篇: 深入浅出WPF——附加事件(Attach