HTTP 服务
如果使用的是 gooze-cli
或者 gen api...
指令生成的代码,那么已经自动实现了 http
服务
此时,只需要确保 main.go
中匿名导入了即可
但是,就算你自行实现,也需要按照 gooze
的要求来
实现
一定要知道的内容
在 gooze
中启动一个 http
服务,必须要做一件事
通过实现接口 gooze.IService
注册你要启动的服务
- 注册服务
go
// 参数必须是一个或多个实现了 IService 接口的对象
gooze.RegisterService(&HttpServer{})
要求:每个对象都必须实现 OnStart() error
方法
- 接口实现
go
type HttpServer struct {
*gooze.IServer
}
func (self *HttpServer) OnStart() (err error) { // 必须实现的方法
// TODO implement
// 实现 http 的初始化
return nil
}
- 在
OnStart()
方法中实现http
的初始化
如何初始化?
通过
gooze
内置的httpmodule
模块初始化自行实现
内置的 httpmodule
模块
内置的 httpmodule
模块提供了几个关键的方法
Init(caller interface{}, addr string, timeout int, engine *gin.Engine)
用来初始化基本参数OnStop(data *gzutil.OrderlyMap)
用来注册服务停机时需要执行的函数
gzutil.OrderlyMap
是什么?
它是一个有序 Map
严格按照 Append
的顺序执行,先进先出,同名会被覆盖,可以确保你停机时执行的函数的顺序
Start() error
用来启动服务StartTLS(certFile, keyFile string) error
用来启动https
服务
所以最终的实现方式就很简单了,如下
go
// server.go
func init() {
gooze.RegisterService(&HttpServer{})
}
type HttpServer struct {
*gooze.IServer
httpModule httpmodule.IHttp // 使用内置的模块
}
func (self *HttpServer) OnStart() (err error) {
// 添加回调函数
self.httpModule.OnStop(self.exitCallback())
self.httpModule.Init(self, gooze.Config.App.Addr, gooze.Config.App.Timeout, router.InitRouter())
err = self.httpModule.Start()
return
}
// TODO 添加回调函数, 无逻辑可直接删除这个方法
func (self *HttpServer) exitCallback() *gzutil.OrderlyMap {
callback := gzutil.NewOrderlyMap()
callback.Append("exit", func() {
gooze.Log.Info("这是程序退出后的回调函数, 执行你想要执行的逻辑, 无逻辑可以直接删除这个方法")
})
return callback
}
自行实现
这个的实现方式也有很多,但是常见的大概如下:
- 服务启动
go
// server.go
func (self *HttpServer) OnStart() (err error) {
// 初始化路由
route := router.InitRouter()
// 启动服务
server := &http.Server{
Addr: ":8080",
Handler: route,
}
go func() {
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
fmt.Println("服务启动失败:", err)
}
}()
shutdown(server)
return nil
}
- 服务停机
go
// server.go
func shutdown(server *http.Server) {
quit := make(chan os.Signal)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
fmt.Println("接收到退出信号,等待当前响应完成...")
// 停机倒计时
timeout := 5
ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(timeout))
defer cancel()
tick := time.Tick(time.Duration(timeout) * time.Second)
for countdown := timeout; countdown > 0; countdown-- {
<-tick
}
if err := server.Shutdown(ctx); err != nil {
fmt.Println("服务停机失败:", err)
}
}
以上两种方式都经过了验证,是完全可用的,任君选择...