Gin 是一个 Golang 的 web 框架,封装使用简单,目前被广泛使用。实际上对于 Golang 而言,web 框架的依赖要远比 Python,Java 之类的要小。因为其自身的 net/http
足够简单,性能也非常不错。那么包括 Gin 在内的各种 Go web 框架出现的意义仅仅只是为了开发方便吗?关于这方面更深层次的探讨可以看这篇文章 ,同时也可以参考我学长博客中的相关内容 。
这里同时推荐一个简洁实用的 Gin 中文文档 。
简而言之,在 Http 连接建立方面,Golang 原生的 net/http
只用了一个简单的服务多路复用器,通过匹配 URL 提供对应的请求响应服务,几乎无法处理当下规范的 RESTful Web 接口;而 Gin 框架则以 前缀树 作为数据结构,使用了多棵 路由树 来实现响应服务与对应 Http 请求的匹配,使得 Gin 框架下的 Http 通信在有更丰富的功能性的前提下,获得了更高的性能。
安装 创建 Gin 项目,控制台输入
1 go get -u github.com/gin-gonic/gin
在 .go
文件中加入依赖
1 2 3 import ( "github.com/gin-gonic/gin" )
一个简单的例子 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package mainimport ( "github.com/gin-gonic/gin" ) func main () { router := gin.Default() router.GET("/" , func (context *gin.Context) { _, err := context.Writer.WriteString("hello world!" ) if err != nil { return } }) err := router.Run(":8080" ) if err != nil { return } }
该程序启动后,浏览器访问 127.0.0.1:8080
将会输出 **hello world!**。
将 Gin 框架接入 Consul 服务发现与 Go-Micro 微服务 通过注册到 Consul 服务发现,无论是服务前端还是微服务端都仅需要知道 Consul 服务器的信息并将服务在其上进行注册。除了服务名, Gin 服务前端和 Go-Micro 微服务端是无法相互了解的(双方都不知道对方的 ip 地址和端口号)。接下来将通过一个例子来说明这是如何实现的。
Consul 服务发现 具体配置操作详见 Golang 微服务实战 - 2. Consul 。在这个例子中, 必须 首先启动 Consul 服务发现。在控制台中输入 consul agent -dev
即可。然后,在浏览器的 http://127.0.0.1:8500/ui/dc1/services
查看 Consul 仪表板
Go-Micro 微服务 在 Golang 微服务实战 - 3. Go-Micro 框架 的基础上,修改 Go-Micro 框架服务端代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package mainimport ( "Micro-Learning/handler" pb "Micro-Learning/proto" "github.com/go-micro/plugins/v4/registry/consul" "go-micro.dev/v4" "go-micro.dev/v4/logger" "go-micro.dev/v4/registry" ) var ( service = "micro-learning" version = "latest" ) func main () { consulReg := consul.NewRegistry(registry.Addrs("127.0.0.1:8500" )) srv := micro.NewService() srv.Init( micro.Name(service), micro.Registry(consulReg), micro.Version(version), ) if err := pb.RegisterMicroLearningHandler(srv.Server(), new (handler.MicroLearning)); err != nil { logger.Fatal(err) } if err := srv.Run(); err != nil { logger.Fatal(err) } }
Go-Micro 框架为了符合 MVC 标准,将业务代码放在了 hanler 文件夹下,其中的业务代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package handlerimport ( "context" "fmt" "go-micro.dev/v4/logger" pb "Micro-Learning/proto" ) type MicroLearning struct {}func (e *MicroLearning) Call(ctx context.Context, req *pb.CallRequest, rsp *pb.CallResponse) error { logger.Infof("Received MicroLearning.Call request: %v" , req) fmt.Printf("Received MicroLearning.Call request: %v\n" , req) rsp.Msg = "Hello " + req.Name return nil }
直接运行 main.go
,控制台出现如下信息说明运行成功,且服务已经注册到了 Consul。
1 2 3 4 2022-10-20 20:21:50 file=Micro-Learning/main.go:35 level=info Starting [service] micro-learning 2022-10-20 20:21:50 file=v4@v4.9.0/service.go:96 level=info Transport [http] Listening on [::]:55163 2022-10-20 20:21:50 file=v4@v4.9.0/service.go:96 level=info Broker [http] Connected to 127.0.0.1:55164 2022-10-20 20:21:50 file=server/rpc_server.go:832 level=info Registry [consul] Registering node: micro-learning-160dc67a-5352-44b1-9b03-84f31f53e889
在 Consul 仪表板 http://127.0.0.1:8500/ui/dc1/services
可以看到 micro-learning 服务已经被注册了。
Gin 服务前端 首先,必须将 Go-Micro 微服务部分项目文件中的文件夹 /proto/
直接拷贝到 Gin 项目文件夹中,不能 自己再重写或者重新编译 protobuf ,因为服务前端和微服务端二者要连通, protobuf 必须完全相同。虽然复制黏贴的操作看起来很蠢, 事实上确实如此, 但在实际生产环境中一般都是服务前端直接在 import
中调用微服务端所在 git 仓库的 protobuf ,此处为了测试和演示方便直接使用复制黏贴即可。
在 一个简单的例子 的基础上修改代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 package mainimport ( pb "Gin-Web/proto" "context" "fmt" "github.com/gin-gonic/gin" "github.com/go-micro/plugins/v4/registry/consul" "go-micro.dev/v4" "go-micro.dev/v4/client" "go-micro.dev/v4/registry" ) func CallRemote (ctx *gin.Context) { consulReg := consul.NewRegistry(registry.Addrs("127.0.0.1:8500" )) srv := micro.NewService() srv.Init( micro.Client(client.NewClient()), micro.Registry(consulReg), ) microLearningService := pb.NewMicroLearningService("micro-learning" , srv.Client()) callResponse, err := microLearningService.Call(context.TODO(), &pb.CallRequest{Name: "Kevin" }) if err != nil { fmt.Println(err) return } respString := callResponse.GetMsg() _, err = ctx.Writer.WriteString(respString) if err != nil { fmt.Println(err) return } } func main () { router := gin.Default() router.GET("/" , CallRemote) err := router.Run(":8090" ) if err != nil { fmt.Println(err) return } }
然后直接运行 Gin 服务前端,在浏览器中访问 http://127.0.0.1:8090/
,输出 Hello Kevin
则说明调用成功。