網關 library-apigateway,介面訪問的統一入口,通過 consul 獲取注冊的微服務的某一個實體,發起訪問請求,如圖:

完整代碼:
https://github.com/Justin02180218/micro-kit
包結構

目前網關的功能只是做介面轉發,所以只有一個 transport 層,
代碼實作
組態檔
server:
port: 80
mode: debug
name: "apigateway"
consul:
addr: "http://consul-server:8500"
interval: "10s"
timeout: "1s"
client:
retrymax: 3
retrytimeout: 500
修改 consul.go
func HttpClient(cfg *configs.AppConfig, name, method, path string, logger log.Logger) endpoint.Endpoint {
consulAddr := cfg.ConsulConfig.Addr
retryMax := cfg.ConsulConfig.Client.RetryMax
retryTimeout := cfg.ConsulConfig.Client.RetryTimeout
client := connectConsul(consulAddr)
instance := consul.NewInstancer(client, logger, name, []string{name}, true)
factory := factoryForHttp(method, path)
endpointer := sd.NewEndpointer(instance, factory, logger)
balancer := lb.NewRoundRobin(endpointer)
retry := lb.Retry(retryMax, time.Millisecond*time.Duration(retryTimeout), balancer)
return retry
}
func factoryForHttp(method, path string) 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
}
tgt.Path = path
return httptransport.NewClient(
method,
tgt,
utils.EncodeJSONRequest,
utils.DecodeJSONResponse,
).Endpoint(), nil, nil
}
}
transport層
在 transport 層定義 NewHttpHandler 函式,回傳 *gin.Engine,目前采用硬編碼的方式添加api介面,后續可以改成頁面配置的方式,
func NewHttpHandler(ctx context.Context, cfg *configs.AppConfig, logger log.Logger) *gin.Engine {
r := utils.NewRouter(ctx.Value("ginMod").(string))
e := r.Group("/api/user")
{
e.POST("register", func(c *gin.Context) {
register := registers.HttpClient(cfg, "user-service", "POST", "/api/v1/register", logger)
kithttp.NewServer(
register,
utils.DecodeJSONRequest,
utils.EncodeJsonResponse,
).ServeHTTP(c.Writer, c.Request)
})
e.GET("findByID", func(c *gin.Context) {
findByID := registers.HttpClient(cfg, "user-service", "GET", "/api/v1/findByID", logger)
kithttp.NewServer(
findByID,
utils.DecodeJSONRequest,
utils.EncodeJsonResponse,
).ServeHTTP(c.Writer, c.Request)
})
e.GET("findByEmail", func(c *gin.Context) {
findByEmail := registers.HttpClient(cfg, "user-service", "GET", "/api/v1/findByEmail", logger)
kithttp.NewServer(
findByEmail,
utils.DecodeJSONRequest,
utils.EncodeJsonResponse,
).ServeHTTP(c.Writer, c.Request)
})
e.GET("findBooksByUserID", func(c *gin.Context) {
findBooksByUserID := registers.HttpClient(cfg, "user-service", "GET", "/api/v1/findBooksByUserID", logger)
kithttp.NewServer(
findBooksByUserID,
utils.DecodeJSONRequest,
utils.EncodeJsonResponse,
).ServeHTTP(c.Writer, c.Request)
})
}
e = r.Group("/api/book")
{
e.POST("save", func(c *gin.Context) {
save := registers.HttpClient(cfg, "book-service", "POST", "/api/v1/save", logger)
kithttp.NewServer(
save,
utils.DecodeJSONRequest,
utils.EncodeJsonResponse,
).ServeHTTP(c.Writer, c.Request)
})
e.GET("books", func(c *gin.Context) {
books := registers.HttpClient(cfg, "book-service", "GET", "/api/v1/books", logger)
kithttp.NewServer(
books,
utils.DecodeJSONRequest,
utils.EncodeJsonResponse,
).ServeHTTP(c.Writer, c.Request)
})
e.GET("selectBookByName", func(c *gin.Context) {
selectBookByName := registers.HttpClient(cfg, "book-service", "GET", "/api/v1/selectBookByName", logger)
kithttp.NewServer(
selectBookByName,
utils.DecodeJSONRequest,
utils.EncodeJsonResponse,
).ServeHTTP(c.Writer, c.Request)
})
e.POST("borrowBook", func(c *gin.Context) {
borrowBook := registers.HttpClient(cfg, "book-service", "POST", "/api/v1/borrowBook", logger)
kithttp.NewServer(
borrowBook,
utils.DecodeJSONRequest,
utils.EncodeJsonResponse,
).ServeHTTP(c.Writer, c.Request)
})
}
return r
}
啟動服務
main.go
var confFile = flag.String("f", "apigateway.yaml", "user config file")
func main() {
flag.Parse()
var logger log.Logger
{
logger = log.NewLogfmtLogger(os.Stderr)
logger = log.With(logger, "ts", log.DefaultTimestampUTC)
logger = log.With(logger, "caller", log.DefaultCaller)
}
err := configs.Init(*confFile)
if err != nil {
panic(err)
}
ctx := context.Background()
ctx = context.WithValue(ctx, "ginMod", configs.Conf.ServerConfig.Mode)
r := transport.NewHttpHandler(ctx, configs.Conf, logger)
errChan := make(chan error)
go func() {
errChan <- r.Run(fmt.Sprintf(":%s", strconv.Itoa(configs.Conf.ServerConfig.Port)))
}()
go func() {
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
errChan <- fmt.Errorf("%s", <-c)
}()
fmt.Println(<-errChan)
}
啟動
進入 library-apigateway 目錄,執行 go run main.go 如圖:

服務成功啟動,監聽80埠
介面測驗
在 /etc/hosts 中配置 api.library.com 域名
使用postman進行介面測驗,在這里進行了 findBooksByUserID 的介面測驗,結果如圖:

下一篇文章,我們在各個服務中加入分布式鏈路追蹤功能,
完整代碼:
https://github.com/Justin02180218/micro-kit
更多【分布式專輯】【架構實戰專輯】系列文章,請關注公眾號

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/305634.html
標籤:其他
上一篇:Shell面試題
