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
account
的proto
相关文件已经在之前的 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":""}