go-kit三层架构

go-kit三层架构

image-20220418201444554

go-kit的架构如图分为三层结构:Transport层,Endpoint层,Service层。

Transport层主要负责与传输协议HTTP,GRPC,THRIFT等相关的逻辑;
Endpoint层主要负责request/response格式的转换,以及公用拦截器相关的逻辑;
Service层则专注于业务逻辑,就是我们的业务类、接口等相关信息存放。
go-kit除了经典的分层架构外,还在endpoint层提供了很多公用的拦截器,如log,metric,tracing,circuitbreaker,rate-limiter等,来保障业务系统的可用性。

img

三层架构代码

image-20220418210147528

UserEndpoint.go:

package Services

import (
   "context"
   "github.com/go-kit/kit/endpoint"
)

type UserRequest struct {
   Uid int `json:"uid"`
}

type UserResponse struct {
   Result string `json:"result"`
}

func GenUserEndpoint(userService IUserService) endpoint.Endpoint {
   return func(ctx context.Context, request interface{}) (response interface{}, err error) {
      r := request.(UserRequest)
      result := userService.GetName(r.Uid)
      return UserResponse{Result: result}, nil
   }
}

UserService.go

package Services

type IUserService interface {
   GetName(userid int) string
}

type UserService struct {
}

func (this UserService) GetName(userid int) string {
   if userid == 101 {
      return "jiang"
   }
   return "tao"
}

UserTransport.go

package Services

import (
	"context"
	"encoding/json"
	"errors"
	"net/http"
	"strconv"
)

func DecodeUserRequest(c context.Context, r *http.Request) (interface{}, error) {
	if r.URL.Query().Get("uid") != "" {
		uid, _ := strconv.Atoi(r.URL.Query().Get("uid"))
		return UserRequest{
			Uid: uid,
		}, nil
	}
	return nil, errors.New("参数错误")
}

func EncodeUserResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
    w.Header().Set("Content-type", "application/json")
	return json.NewEncoder(w).Encode(response)
}

main.go

package main

import (
   httptransport "github.com/go-kit/kit/transport/http"
   "go-kit/Services"
   "net/http"
)

func main() {
   user := Services.UserService{}
   endp := Services.GenUserEndpoint(user)

   serverHandler := httptransport.NewServer(endp, Services.DecodeUserRequest, Services.EncodeUserResponse)

   http.ListenAndServe(":8080", serverHandler)
}

image-20220418210844775

第三方包配置路由

实现RESTFUL风格

go get -u github.com/gorilla/mux

代码改造

main.go

package main

import (
   httptransport "github.com/go-kit/kit/transport/http"
   mymux "github.com/gorilla/mux"
   "go-kit/Services"
   "net/http"
)

func main() {
   user := Services.UserService{}
   endp := Services.GenUserEndpoint(user)

   serverHandler := httptransport.NewServer(endp, Services.DecodeUserRequest, Services.EncodeUserResponse)

   r := mymux.NewRouter()
   //r.Handle(`/user/{uid:\d+}`, serverHandler)
   r.Methods("GET").Path(`/user/{uid:\d+}`).Handler(serverHandler)

   http.ListenAndServe(":8080", r)
}

UserTransport.go

package Services

import (
   "context"
   "encoding/json"
   "errors"
   mymux "github.com/gorilla/mux"
   "net/http"
   "strconv"
)

func DecodeUserRequest(c context.Context, r *http.Request) (interface{}, error) {

   vars := mymux.Vars(r)

   if uid, ok := vars["uid"]; ok {
      uid, _ := strconv.Atoi(uid)
      return UserRequest{
         Uid: uid,
      }, nil
   }
   return nil, errors.New("参数错误")
}

func EncodeUserResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
   w.Header().Set("Content-type", "application/json")
   return json.NewEncoder(w).Encode(response)
}

实现多种方法

main.go

package main

import (
   httptransport "github.com/go-kit/kit/transport/http"
   mymux "github.com/gorilla/mux"
   "go-kit/Services"
   "net/http"
)

func main() {
   user := Services.UserService{}
   endp := Services.GenUserEndpoint(user)

   serverHandler := httptransport.NewServer(endp, Services.DecodeUserRequest, Services.EncodeUserResponse)

   r := mymux.NewRouter()
   //r.Handle(`/user/{uid:\d+}`, serverHandler)
   r.Methods("GET", "DELETE").Path(`/user/{uid:\d+}`).Handler(serverHandler)

   http.ListenAndServe(":8080", r)
}

UserTransport.go

package Services

import (
   "context"
   "encoding/json"
   "errors"
   mymux "github.com/gorilla/mux"
   "net/http"
   "strconv"
)

func DecodeUserRequest(c context.Context, r *http.Request) (interface{}, error) {

   vars := mymux.Vars(r)

   if uid, ok := vars["uid"]; ok {
      uid, _ := strconv.Atoi(uid)
      return UserRequest{
         Uid:    uid,
         Method: r.Method,
      }, nil
   }
   return nil, errors.New("参数错误")
}

func EncodeUserResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
   w.Header().Set("Content-type", "application/json")
   return json.NewEncoder(w).Encode(response)
}

UserService.go

package Services

import "errors"

type IUserService interface {
   GetName(userid int) string
   DelUser(userid int) error
}

type UserService struct {
}

func (this UserService) GetName(userid int) string {
   if userid == 101 {
      return "jiang"
   }
   return "tao"
}

func (this UserService) DelUser(userid int) error {
   if userid == 101 {
      return errors.New("无权限")
   }
   return nil
}

UserEndpoint.go

package Services

import (
   "context"
   "fmt"
   "github.com/go-kit/kit/endpoint"
)

type UserRequest struct {
   Uid    int `json:"uid"`
   Method string
}

type UserResponse struct {
   Result string `json:"result"`
}

func GenUserEndpoint(userService IUserService) endpoint.Endpoint {
   return func(ctx context.Context, request interface{}) (response interface{}, err error) {
      r := request.(UserRequest)
      result := "nothing"
      if r.Method == "GET" {
         result = userService.GetName(r.Uid)
      } else if r.Method == "DELETE" {
         err := userService.DelUser(r.Uid)
         if err != nil {
            result = err.Error()
         } else {
            result = fmt.Sprintf("userid为%d删除成功", r.Uid)
         }
      }

      return UserResponse{Result: result}, nil
   }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于go-kit的简单例子: ``` package main import ( "context" "fmt" "net/http" "os" "os/signal" "syscall" "time" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/go-kit/kit/transport/http" ) func main() { var logger log.Logger { logger = log.NewLogfmtLogger(os.Stderr) logger = log.With(logger, "timestamp", log.DefaultTimestampUTC) logger = log.With(logger, "caller", log.DefaultCaller) } var ( listenAddr = ":8080" ) var svc Service { svc = myService{} svc = loggingMiddleware(logger)(svc) } var uppercaseHandler http.Handler { uppercaseHandler = http.NewServer( makeUppercaseEndpoint(svc), decodeUppercaseRequest, encodeResponse, ) } http.Handle("/uppercase", uppercaseHandler) errs := make(chan error, 2) go func() { c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) errs <- fmt.Errorf("%s", <-c) }() go func() { level.Info(logger).Log("msg", "HTTP", "addr", listenAddr) errs <- http.ListenAndServe(listenAddr, nil) }() level.Error(logger).Log("exit", <-errs) } // Service provides a simple string manipulation service. type Service interface { Uppercase(context.Context, string) (string, error) } type myService struct{} func (myService) Uppercase(_ context.Context, s string) (string, error) { if s == "" { return "", ErrEmpty } return strings.ToUpper(s), nil } func makeUppercaseEndpoint(svc Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(uppercaseRequest) v, err := svc.Uppercase(ctx, req.S) if err != nil { return uppercaseResponse{v, err.Error()}, nil } return uppercaseResponse{v, ""}, nil } } type uppercaseRequest struct { S string `json:"s"` } type uppercaseResponse struct { V string `json:"v"` Err string `json:"err,omitempty"` } func decodeUppercaseRequest(_ context.Context, r *http.Request) (interface{}, error) { var request uppercaseRequest if err := json.NewDecoder(r.Body).Decode(&request); err != nil { return nil, err } return request, nil } func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { return json.NewEncoder(w).Encode(response) } func loggingMiddleware(logger log.Logger) Middleware { return func(next Service) Service { return logmw{logger, next} } } type Middleware func(Service) Service type logmw struct { logger log.Logger next Service } func (mw logmw) Uppercase(ctx context.Context, s string) (output string, err error) { defer func(begin time.Time) { level.Info(mw.logger).Log( "method", "uppercase", "input", s, "output", output, "err", err, "took", time.Since(begin), ) }(time.Now()) output, err = mw.next.Uppercase(ctx, s) return } var ErrEmpty = errors.New("empty string") ``` 这个例子中定义了一个Service,提供了一个Uppercase方法,将输入字符串转换为大写。使用go-kit的httptransport将该方法封装成HTTP API。另外,还增加了一个loggingMiddleware,用于日志记录。 其中,Service、Endpoint和Middleware是go-kit的核心概念,用于实现微服务的组件化。Middleware用于对Service进行装饰,Endpoint用于将Service的方法封装成一个HTTP API,具有了统一的传输层约定。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值