2.4 网关编写

未匹配的标注

作用

上一章中,我们已经编写好了account服务。这一章我们来完成apigateway,也就是网关的编写。

我们将会使用gin框架,来对外提供HTTP服务与路由。一个url请求进入后,gin框架的路由解析后找到对应的handler方法,然后该handler中会调用对应的服务,获得最终的结果,返回给用户。

对外HTTP,对内RPC

目录结构

我们来看一下apigateway的最终目录结构

├─apigateway
  ├─deploy                   (部署相关)
  ├─handler
    └─account.go
  ├─proto                    (proto文件)
    ├─account
      ├─account.pb.go           
      └─account.pb.micro.go     
  ├─router                    (路由)
    └─router.go
  ├─serviceclient             (client)
    └─init.go   
  ├─apigw.go                  (入口文件)
  ├─go.mod
  └─go.sum

文件夹大家根据结构自行创建~

编写

好,那我们现在开始编写相关文件。

最终的代码和部署文件,已经传至github,欢迎star。

github.com/guaosi/go-micro-build

proto

accountproto相关文件已经在之前的 GO微服务系列-2.1 proto文件的编写与生成 已经编写并且成功好了,我们复制到proto文件夹中即可。

Client

serviceclient/init.go

package serviceclient

import (
    "apigw/handler"
    proto "apigw/proto/account"
    "github.com/micro/cli/v2"
    "github.com/micro/go-micro/v2"
    // 这里使用 kubernetes 是为了之后可以通过命令行指定注册中心用 kubernetes
    _ "github.com/micro/go-plugins/registry/kubernetes/v2"
)

var Port string

func RegisterService() {
    // 连接服务注册中心
    service := micro.NewService(
        micro.Flags(
            &cli.StringFlag{
                Name:  "p",
                Usage: "port",
            },
        ),
    )
    // 解析命令行参数
    // 我们希望可以使用 -p 参数来手动指定我们HTTP服务对外提供服务时的端口
    service.Init(
        micro.Action(func(c *cli.Context) error {
            Port = c.String("p")
            if len(Port) == 0 {
                Port = "8091"
            }
            return nil
        },
        ),
    )
    // 复用服务注册的客户端
    cli := service.Client()
    // 获取在服务注册中心上 micro.service.account 的客户端
    handler.AccountServiceClient = proto.NewAccountService("micro.service.account", cli)
}

handler

handler/account.go

package handler

import (
    proto "apigw/proto/account"
    "context"
    "github.com/gin-gonic/gin"
    "log"
    "net/http"
)

var (
    AccountServiceClient proto.AccountService
)

func RegisterHandler(c *gin.Context) {
    username := c.PostForm("username")
    password := c.PostForm("password")
    // 通过AccountService服务的client,调用 AccountRegister 方法
    res, err := AccountServiceClient.AccountRegister(context.TODO(), &proto.ReqAccountRegister{
        Username: username,
        Password: password,
    })
    if err != nil {
        log.Print(err.Error())
        c.JSON(http.StatusInternalServerError, gin.H{
            "code":    -2,
            "message": "server error",
        })
        return
    }
    c.JSON(http.StatusOK, gin.H{
        "code":    res.Code,
        "message": res.Message,
    })
    return
}

编写路由

router/router.go

package router

import (
    "apigw/handler"
    "github.com/gin-gonic/gin"
)

func NewRouter() *gin.Engine {
    route := gin.Default()
    route.POST("/account/register", handler.RegisterHandler)
    return route
}

开启HTTP服务

apigw.go

package main

import (
    "apigw/router"
    "apigw/serviceclient"
    "log"
)

func init() {
    serviceclient.RegisterService()
}
func main() {
    r := router.NewRouter()
    if err := r.Run("0.0.0.0:" + serviceclient.Port); err != nil {
        log.Print(err.Error())
    }
}

编写完毕后,我们运行直接指定以8091作为端口启动http服务,并且服务发现和注册切换为etcd

go run . -p 8091 --registry etcd

记得要启动我们上一章编写的account服务哦~

开启成功后,我们发送curl请求,进行验证

> curl -X POST -d "username=guaosi&password=guaosi" http://127.0.0.1:8091/account/register

{"code":0,"message":""}

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~