今天我们来做一个有趣的 Go 实践。使用同一套代码,在一个进程中,同时启动 7种不同的 Go Web 框架。
为什么做这么无聊的事儿?
主要目的就是介绍 rookie-ninja/rk-boot 库。
我们同时启动如下几个 Go Web 框架。
Web 框架 | rk-boot 依赖 | 版本 |
---|---|---|
go get github.com/rookie-ninja/rk-boot/gin | v1.2.14 (Stable) | |
go get github.com/rookie-ninja/rk-boot/grpc | v1.2.18 (Stable) | |
go get github.com/rookie-ninja/rk-boot/echo | v0.0.8 (Stable) | |
go get github.com/rookie-ninja/rk-boot/gf | v0.0.6 (Stable) | |
go get github.com/rookie-ninja/rk-boot/fiber | v0.0.4 (Testing) | |
go get github.com/rookie-ninja/rk-boot/zero | v0.0.2 (Testing) | |
go get github.com/rookie-ninja/rk-boot/mux | v0.0.2 (Testing) |
我们通过 go get 安装如下依赖。
go get github.com/rookie-ninja/rk-boot/grpc
go get github.com/rookie-ninja/rk-boot/gin
go get github.com/rookie-ninja/rk-boot/echo
go get github.com/rookie-ninja/rk-boot/gf
go get github.com/rookie-ninja/rk-boot/fiber
go get github.com/rookie-ninja/rk-boot/zero
go get github.com/rookie-ninja/rk-boot/mux
Web 框架 | 端口 |
---|---|
8081 | |
8082 | |
8083 | |
8084 | |
8085 | |
8086 | |
8087 |
除了指定端口,我们还开启了如下两个选项:
---
grpc:
- name: grpc
port: 8081
enabled: true
commonService:
enabled: true # Optional, default: false
interceptors:
loggingZap:
enabled: true # Optional, default: false
gin:
- name: gin
port: 8082
enabled: true
commonService:
enabled: true # Optional, default: false
interceptors:
loggingZap:
enabled: true # Optional, default: false
echo:
- name: echo
port: 8083
enabled: true
commonService:
enabled: true # Optional, default: false
interceptors:
loggingZap:
enabled: true # Optional, default: false
gf:
- name: gf
port: 8084
enabled: true
commonService:
enabled: true # Optional, default: false
interceptors:
loggingZap:
enabled: true # Optional, default: false
fiber:
- name: fiber
port: 8085
enabled: true
commonService:
enabled: true # Optional, default: false
interceptors:
loggingZap:
enabled: true # Optional, default: false
zero:
- name: zero
port: 8086
enabled: true
commonService:
enabled: true # Optional, default: false
interceptors:
loggingZap:
enabled: true # Optional, default: false
mux:
- name: mux
port: 8087
enabled: true
commonService:
enabled: true # Optional, default: false
interceptors:
loggingZap:
enabled: true # Optional, default: false
所有 Web 框架都是用 handleRequest() 函数来处理请求。
gRPC 例外,我们没有使用 protocol buffer,因为 PB 的协议不同。我们使用 grpc-gateway 来模拟。
grpcEntry 默认会开启 grpc-gateway,通过 grpcEntry.HttpMux 往 grpc-gateway 里注册 API。
// Copyright (c) 2021 rookie-ninja
//
// Use of this source code is governed by an Apache-style
// license that can be found in the LICENSE file.
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"github.com/gofiber/adaptor/v2"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/labstack/echo/v4"
"github.com/rookie-ninja/rk-boot"
"github.com/rookie-ninja/rk-boot/echo"
"github.com/rookie-ninja/rk-boot/fiber"
"github.com/rookie-ninja/rk-boot/gf"
"github.com/rookie-ninja/rk-boot/gin"
"github.com/rookie-ninja/rk-boot/grpc"
"github.com/rookie-ninja/rk-boot/mux"
"github.com/rookie-ninja/rk-boot/zero"
"github.com/tal-tech/go-zero/rest"
"net/http"
)
const handlePath = "/v1/hello"
// Application entrance.
func main() {
// Create a new boot instance.
boot := rkboot.NewBoot()
// 6: go-zero @8086, must adds route before bootstrap
rkbootzero.GetZeroEntry("zero").Server.AddRoute(rest.Route{
Method: http.MethodGet,
Path: handlePath,
Handler: handleRequest,
})
// Bootstrap
boot.Bootstrap(context.Background())
// 1: grpc-gateway @8081
rkbootgrpc.GetGrpcEntry("grpc").HttpMux.HandleFunc(handlePath, handleRequest)
// 2: gin @8082
rkbootgin.GetGinEntry("gin").Router.Handle(http.MethodGet, handlePath, gin.WrapF(handleRequest))
// 3: echo @8083
rkbootecho.GetEchoEntry("echo").Echo.GET(handlePath, echo.WrapHandler(http.HandlerFunc(handleRequest)))
// 4: GoFrame @8084
rkbootgf.GetGfEntry("gf").Server.BindHandler(handlePath, ghttp.WrapF(handleRequest))
// 5: Fiber @8085, must call RefreshFiberRoutes()
rkbootfiber.GetFiberEntry("fiber").App.Get(handlePath, adaptor.HTTPHandler(http.HandlerFunc(handleRequest)))
rkbootfiber.GetFiberEntry("fiber").RefreshFiberRoutes()
// 7: mux @8087
rkbootmux.GetMuxEntry("mux").Router.HandleFunc(handlePath, handleRequest)
// Wait for shutdown sig
boot.WaitForShutdownSig(context.Background())
}
// Handle request for all web frameworks
func handleRequest(writer http.ResponseWriter, req *http.Request) {
// 1: get query
name := req.URL.Query().Get("name")
// 2: marshal response
bytes, _ := json.Marshal(&Response{
Message: fmt.Sprintf("Hello %s", name),
})
// 3: write response
writer.WriteHeader(http.StatusOK)
writer.Write(bytes)
}
type Response struct {
Message string `json:"message"`
}
.
├── boot.yaml
├── go.mod
├── go.sum
└── main.go
0 directories, 4 files
module github.com/rookie-ninja/rk-demo
go 1.16
require (
github.com/gin-gonic/gin v1.7.7
github.com/gofiber/adaptor/v2 v2.1.15
github.com/gogf/gf/v2 v2.0.0-beta
github.com/labstack/echo/v4 v4.6.1
github.com/rookie-ninja/rk-boot v1.4.0
github.com/rookie-ninja/rk-boot/echo v0.0.8
github.com/rookie-ninja/rk-boot/fiber v0.0.4
github.com/rookie-ninja/rk-boot/gf v0.0.6
github.com/rookie-ninja/rk-boot/gin v1.2.14
github.com/rookie-ninja/rk-boot/grpc v1.2.18
github.com/rookie-ninja/rk-boot/mux v0.0.2
github.com/rookie-ninja/rk-boot/zero v0.0.2
github.com/tal-tech/go-zero v1.2.4
)
$ go run main.go
2022-01-03T19:15:14.016+0800 INFO boot/gf_entry.go:1050 Bootstrap gfEntry {"eventId": "264033ff-be9c-4147-871c-e4873ea1510d", "entryName": "gf"}
------------------------------------------------------------------------
endTime=2022-01-03T19:15:14.016473+08:00
startTime=2022-01-03T19:15:14.016057+08:00
elapsedNano=416178
timezone=CST
ids={"eventId":"264033ff-be9c-4147-871c-e4873ea1510d"}
app={"appName":"rk","appVersion":"","entryName":"gf","entryType":"GfEntry"}
env={"arch":"amd64","az":"*","domain":"*","hostname":"lark.local","localIP":"10.8.0.2","os":"darwin","realm":"*","region":"*"}
payloads={"commonServiceEnabled":true,"commonServicePathPrefix":"/rk/v1/","gfPort":8084}
error={}
counters={}
pairs={}
timing={}
remoteAddr=localhost
operation=Bootstrap
resCode=OK
eventStatus=Ended
EOE
...
调用 /rk/v1/healthy 来确定服务是否启动。
$ curl localhost:8081/rk/v1/healthy
{"healthy":true}
$ curl localhost:8082/rk/v1/healthy
{"healthy":true}
$ curl localhost:8083/rk/v1/healthy
{"healthy":true}
$ curl localhost:8084/rk/v1/healthy
{"healthy":true}
$ curl localhost:8085/rk/v1/healthy
{"healthy":true}
$ curl localhost:8086/rk/v1/healthy
{"healthy":true}
$ curl localhost:8087/rk/v1/healthy
{"healthy":true}
我们将会发送 /v1/hello 请求到各个端口,并查看 RPC 日志。
$ curl "localhost:8081/v1/hello?name=rk-dev"
{"message":"Hello rk-dev"}
$ curl "localhost:8082/v1/hello?name=rk-dev"
{"message":"Hello rk-dev"}
# RPC log from server side
------------------------------------------------------------------------
endTime=2022-01-03T19:18:26.23983+08:00
startTime=2022-01-03T19:18:26.239805+08:00
elapsedNano=25460
timezone=CST
ids={"eventId":"0d284016-f714-4c85-8af8-9715dc9ed35f"}
app={"appName":"rk","appVersion":"","entryName":"gin","entryType":"GinEntry"}
env={"arch":"amd64","az":"*","domain":"*","hostname":"lark.local","localIP":"10.8.0.2","os":"darwin","realm":"*","region":"*"}
payloads={"apiMethod":"GET","apiPath":"/v1/hello","apiProtocol":"HTTP/1.1","apiQuery":"name=rk-dev","userAgent":"curl/7.64.1"}
error={}
counters={}
pairs={}
timing={}
remoteAddr=localhost:54102
operation=/v1/hello
resCode=200
eventStatus=Ended
EOE
$ curl "localhost:8082/v1/hello?name=rk-dev"
{"message":"Hello rk-dev"}
# RPC log from server side
------------------------------------------------------------------------
endTime=2022-01-03T19:19:11.109838+08:00
startTime=2022-01-03T19:19:11.109817+08:00
elapsedNano=21242
timezone=CST
ids={"eventId":"34419c7c-1a78-484f-ba7a-bfca69178b82"}
app={"appName":"rk","appVersion":"","entryName":"echo","entryType":"EchoEntry"}
env={"arch":"amd64","az":"*","domain":"*","hostname":"lark.local","localIP":"10.8.0.2","os":"darwin","realm":"*","region":"*"}
payloads={"apiMethod":"GET","apiPath":"/v1/hello","apiProtocol":"HTTP/1.1","apiQuery":"name=rk-dev","userAgent":"curl/7.64.1"}
error={}
counters={}
pairs={}
timing={}
remoteAddr=localhost:56995
operation=/v1/hello
resCode=200
eventStatus=Ended
EOE
$ curl "localhost:8084/v1/hello?name=rk-dev"
{"message":"Hello rk-dev"}
# RPC log from server side
------------------------------------------------------------------------
endTime=2022-01-03T19:19:39.905883+08:00
startTime=2022-01-03T19:19:39.905858+08:00
elapsedNano=24703
timezone=CST
ids={"eventId":"58bf8706-09ff-434e-b405-d6cdb8dbe8c2"}
app={"appName":"rk","appVersion":"","entryName":"gf","entryType":"GfEntry"}
env={"arch":"amd64","az":"*","domain":"*","hostname":"lark.local","localIP":"10.8.0.2","os":"darwin","realm":"*","region":"*"}
payloads={"apiMethod":"GET","apiPath":"/v1/hello","apiProtocol":"HTTP/1.1","apiQuery":"name=rk-dev","userAgent":"curl/7.64.1"}
error={}
counters={}
pairs={}
timing={}
remoteAddr=localhost:58802
operation=/v1/hello
resCode=200
eventStatus=Ended
EOE
$ curl "localhost:8085/v1/hello?name=rk-dev"
{"message":"Hello rk-dev"}
# RPC log from server side
------------------------------------------------------------------------
endTime=2022-01-03T19:20:48.834567+08:00
startTime=2022-01-03T19:20:48.834425+08:00
elapsedNano=142332
timezone=CST
ids={"eventId":"a98a6e9f-6519-4ded-971e-0b6e59f66096"}
app={"appName":"rk","appVersion":"","entryName":"fiber","entryType":"FiberEntry"}
env={"arch":"amd64","az":"*","domain":"*","hostname":"lark.local","localIP":"10.8.0.2","os":"darwin","realm":"*","region":"*"}
payloads={"apiMethod":"GET","apiPath":"/v1/hello","apiProtocol":"http","apiQuery":"name=rk-dev","userAgent":"curl/7.64.1"}
error={}
counters={}
pairs={}
timing={}
remoteAddr=127.0.0.1:63237
operation=/v1/hello
resCode=200
eventStatus=Ended
EOE
$ curl "localhost:8086/v1/hello?name=rk-dev"
{"message":"Hello rk-dev"}
# RPC log from server side
------------------------------------------------------------------------
endTime=2022-01-03T19:21:20.835415+08:00
startTime=2022-01-03T19:21:20.835391+08:00
elapsedNano=24495
timezone=CST
ids={"eventId":"a6a53d21-4cf4-4b45-97ca-2b190e438e9c","traceId":"bf7a2359d0813de4388dd11c4f161321"}
app={"appName":"rk","appVersion":"","entryName":"zero","entryType":"ZeroEntry"}
env={"arch":"amd64","az":"*","domain":"*","hostname":"lark.local","localIP":"10.8.0.2","os":"darwin","realm":"*","region":"*"}
payloads={"apiMethod":"GET","apiPath":"/v1/hello","apiProtocol":"HTTP/1.1","apiQuery":"name=rk-dev","userAgent":"curl/7.64.1"}
error={}
counters={}
pairs={}
timing={}
remoteAddr=localhost:65299
operation=/v1/hello
resCode=200
eventStatus=Ended
EOE
$ curl "localhost:8086/v1/hello?name=rk-dev"
{"message":"Hello rk-dev"}
# RPC log from server side
------------------------------------------------------------------------
endTime=2022-01-03T19:22:13.13191+08:00
startTime=2022-01-03T19:22:13.131889+08:00
elapsedNano=21449
timezone=CST
ids={"eventId":"8a0f2db6-8e13-4773-bedd-962060adbe41"}
app={"appName":"rk","appVersion":"","entryName":"mux","entryType":"MuxEntry"}
env={"arch":"amd64","az":"*","domain":"*","hostname":"lark.local","localIP":"10.8.0.2","os":"darwin","realm":"*","region":"*"}
payloads={"apiMethod":"GET","apiPath":"/v1/hello","apiProtocol":"HTTP/1.1","apiQuery":"name=rk-dev","userAgent":"curl/7.64.1"}
error={}
counters={}
pairs={}
timing={}
remoteAddr=127.0.0.1:52277
operation=/v1/hello
resCode=200
eventStatus=Ended
EOE
rk-boot 是一个可通过 YAML 启动多种 Web 服务的框架。
有点类似于 Spring boot。通过集成 rk-xxx 系列库,可以启动多种 Web 框架。当然,用户也可以自定义 rk-xxx 库集成到 rk-boot 中。
欢迎贡献新的 Web 框架到 rk-boot 系列中。
框架 | 开发状态 | 安装 | 依赖 |
---|---|---|---|
Stable | go get github.com/rookie-ninja/rk-boot/gin | ||
Stable | go get github.com/rookie-ninja/rk-boot/grpc | ||
Stable | go get github.com/rookie-ninja/rk-boot/echo | ||
Stable | go get github.com/rookie-ninja/rk-boot/gf | ||
Testing | go get github.com/rookie-ninja/rk-boot/fiber | ||
Testing | go get github.com/rookie-ninja/rk-boot/zero | ||
Testing | go get github.com/rookie-ninja/rk-boot/mux |
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有