Home / PostsPost
golang consul 实现简简易的api网关
嘟噜聪2022/04/02 11:03:05 [Golang] [kplcloud] [go] [go-kit] [consul] [registry] [注册中心] [服务发现] [gateway] [网关] 2000人已阅
简介 将consul作为服务作为注册中心实现服务发现> 本期介绍如何通过go-kit写一个简易的网关代理## 微服务> 微服务架构是一种应用架构类型,其中应用会开发为一系列服务。它提供了独立
golang consul 实现简简易的api网关
将consul作为服务作为注册中心实现服务发现
本期介绍如何通过go-kit写一个简易的网关代理
微服务
微服务架构是一种应用架构类型,其中应用会开发为一系列服务。它提供了独立开发、部署和维护微服务架构图和服务的框架。
在微服务架构中,每个微服务都是独立的服务,旨在容纳一种应用特性并处理离散的任务。每个微服务都通过简单的接口与其他服务通信,以解决业务问题。
简单的微服务架构
简单的架构就是服务网关作为统一出入口。
服务网关不紧紧对流量进行转发还能增加鉴权、审计、告警等功能。
以下案例是将用户中心、订单中心、支付中心拆成了多个服务,每个服务可以独立部署、扩容等。
微服务启动时向consul将自己的信息如ip:端口、名称、check地址等等信息发送给consul,consul会对你这注册的服务进行健康检查等。
网关服务除了将自己注册到consul之外还需实时监听相关服务的变更信息并同步到网关服务。
所有外部流量经过网关鉴权之后根据相关规则转发到应用的服务。
实践
网关实践
本案例主要以http的方式作为演示,grpc的方式这边暂时不做演示,以后有机会再来讲解go-kit grpc网关的使用。
// main.go
import (
"log"
consulsd "github.com/go-kit/kit/sd/consul"
consulapi "github.com/hashicorp/consul/api"
"github.com/go-kit/kit/endpoint"
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/sd"
"github.com/go-kit/kit/sd/lb"
"github.com/gorilla/mux"
"net/http"
)
func main() {
logger = log.NewLogfmtLogger(log.StdlibWriter{})
// 连接到consul
consulConfig := consulapi.DefaultConfig()
consulConfig.Address = "consul address"
consulConfig.Token = "consul token" consulClient, err := consulapi.NewClient(consulConfig)
if err != nil {
log.Println(err)
os.Exit(1)
}
client = consulsd.NewClient(consulClient)
var (
opts = []kithttp.ServerOption{
kithttp.ServerErrorEncoder(encode.JsonError),
kithttp.ServerBefore(func(ctx context.Context, request *http.Request) context.Context {
return ctx
}),
}
clientOpts = []kithttp.ClientOption{
kithttp.SetClient(nil), // 设置请求客户端
// kithttp.ClientBefore(kittracing.ContextToHTTP(tracer, logger)), // 链路追踪设置
}
authEms = [] endpoint.Middleware{
// 审计等操作
// 用户鉴权验证
}
retryMax = 2
retryTimeout = time.Second * 5
)
userInstancer := consulsd.NewInstancer(client, logger, "your user service name", []string{}, true)
userFactory := serviceFactory(clientOpts)
userEndpointer := sd.NewEndpointer(userInstancer, userFactory, logger)
userBalancer := lb.NewRoundRobin(userEndpointer) // 负载均衡
userRetry := lb.Retry(retryMax, retryTimeout, userBalancer) // 重试策略
// kittracing.TraceClient(tracer, "paas-api")(userRetry) 如果需要tracer的话,加上
r := mux.NewRouter()
r.PathPrefix("/user").
Handler(http.StripPrefix("/user", userMakeHTTPHandler(userRetry, authEms, opts)))
http.Handle("/", r)
return http.ListenAndServe(":8080", nil)
}
// factory.go
import (
"context"
"encoding/json"
"github.com/go-kit/kit/endpoint"
"github.com/go-kit/kit/sd"
kithttp "github.com/go-kit/kit/transport/http"
"github.com/pkg/errors"
"io"
"net/http"
"net/url"
"strings"
)
func serviceFactory(opts []kithttp.ClientOption) sd.Factory {
return func(instance string) (endpoint.Endpoint, io.Closer, error) {
if !strings.HasPrefix(instance, "http") {
instance = "http://" + instance
}
tgt, err := url.Parse(instance)
if err != nil {
return nil, nil, err
}
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(*http.Request)
tgt.Path = req.URL.Path
tgt.RawQuery = req.URL.RawQuery
eps := kithttp.NewClient(req.Method, tgt, func(ctx context.Context, r *http.Request, request interface{}) error {
r.WithContext(ctx)
sourceReq := request.(*http.Request)
r.Header = sourceReq.Header
r.Body = sourceReq.Body
return nil
}, func(ctx context.Context, res *http.Response) (response interface{}, err error) {
if res.StatusCode != http.StatusOK {
return nil, errors.New(res.Status)
}
// 这里可以做一些 操作,如果返回的结果有问题直接向上抛err
// 这只是个例子,有些情况是各个子服务返回的结果不一致,需要在这里进行处理
var b []byte
if res.Body != nil {
// 返回的数据结构没有统一无法做解析
b, err = ioutil.ReadAll(res.Body)
}
return Response{
Code: res.StatusCode,
Body: b,
HttpHeaders: res.Header.Clone(),
}, err
},
opts...,
).Endpoint()
resp, err := eps(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "kithttp.client")
}
return resp, nil
}, nil, nil
}
}
import (
"context"
"github.com/go-kit/kit/endpoint"
kithttp "github.com/go-kit/kit/transport/http"
"gitlab.creditease.corp/paas/gateway/src/encode"
"net/http"
"github.com/pkg/errors"
"strings"
)
func userMakeHTTPHandler(svc endpoint.Endpoint, dmw []endpoint.Middleware, opts []kithttp.ServerOption) http.Handler {
for _, m := range dmw {
svc = m(svc)
}
return kithttp.NewServer(
svc,
func(ctx context.Context, req *http.Request) (request interface{}, err error) {
return req, nil
},
JsonResponse,
opts...,
)
}
func JsonResponse(ctx context.Context, w http.ResponseWriter, response interface{}) (err error) {
// 对返回结果前的处理
return kithttp.EncodeJSONResponse(ctx, w, resp)
}
type Response struct {
Success bool `json:"success"`
Code int `json:"code"`
Data interface{} `json:"data,omitempty"`
Error string `json:"message,omitempty"`
TraceId string `json:"traceId"`
HttpHeaders http.Header `json:"-"`
StatusCode int `json:"-"`
Body []byte `json:"-"`
}
func (r Response) Headers() http.Header {
return r.HttpHeaders
}
func (r Response) StatusCoder() int {
return r.StatusCode
}
尾巴
不用多说了,懂的都懂。
很赞哦! (5)
下一篇:go-kit 简易图型验证码