当我们使用go-zero开发单体服务时,可能会遇到需要注册多个handler路由的情况,而这些handler的参数和返回值类型往往是类似的,这时就可以考虑使用泛型来简化注册过程。
具体步骤如下:
- 创建接口定义
首先,我们需要定义一个公共的接口,该接口包含了参数和返回值类型相同的方法定义,如下所示:
type CommonService interface {
Ping(ctx context.Context, req *model.Request) (*model.Response, error)
}
该接口定义了一个名为Ping的方法,接收两个参数,分别是上下文和请求参数,返回两个值,即响应结果和错误。
- 实现接口方法
接下来,我们需要为要使用泛型注册的handler实现CommonService接口中的方法,代码示例如下:
type CommonServiceImpl struct {
// 这里是服务实现的具体实现部分
}
func (s *CommonServiceImpl) Ping(ctx context.Context, req *model.Request) (*model.Response, error) {
// 具体实现部分
}
- 注册handler路由
接下来,我们可以定义一个函数,使用go-zero的Go应用程序框架中的泛型函数NewHandler(T)来注册handler路由。这里的“T”就是我们定义的CommonService接口,这样就可以将实现该接口的handler路由动态注册进来。
具体代码示例如下:
func RegisterCommonServiceRoutes(engine *http.Server, svc CommonService) {
registration.AddHandler(func(ctx *svccontext.ServiceContext) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var (
err error
req *model.Request
resp *model.Response
decoder = json.NewDecoder(r.Body)
)
if err = decoder.Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
defer r.Body.Close()
resp, err = svc.Ping(r.Context(), req)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(resp)
})
})
}
在上面的代码中,我们使用了go-zero提供的注册器registration.AddHandler()函数,将handler路由动态添加进去。注意,这里的参数ctx是ServiceContext类型的,而不是常规的context.Context类型,所以我们将它进行了转换。
- 启动应用程序
最后,我们需要从main函数中启动应用程序并注册handler路由。具体示例如下:
func main() {
app := gozero.NewApp()
engine := http.NewServer()
svc := &CommonServiceImpl{}
RegisterCommonServiceRoutes(engine, svc)
app.Use(engine)
app.Start()
}
在上面的代码中,我们定义了一个标准的go-zero应用程序,并将我们之前定义的engine加入到了app.Use()的中间件链中。最后启动app.Start()即可。
示例:
假设我们有两个handler路由,分别是HandleA和HandleB,它们的请求和响应参数类型都相同,我们就可以定义一个公共的接口CommonService来实现它们。
type CommonService interface {
HandleA(ctx context.Context, req *model.Request) (*model.Response, error)
HandleB(ctx context.Context, req *model.Request) (*model.Response, error)
}
接下来,我们为要使用泛型注册的handler实现CommonService接口中的方法:
type CommonServiceImpl struct {
// 这里是具体实现部分
}
func (s *CommonServiceImpl) HandleA(ctx context.Context, req *model.Request) (*model.Response, error) {
// 具体实现部分
}
func (s *CommonServiceImpl) HandleB(ctx context.Context, req *model.Request) (*model.Response, error) {
// 具体实现部分
}
最后,我们可以注册handler路由:
func RegisterCommonServiceRoutes(engine *http.Server, svc CommonService) {
registration.AddHandler(func(ctx *svccontext.ServiceContext) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var (
err error
req *model.Request
resp *model.Response
decoder = json.NewDecoder(r.Body)
)
if err = decoder.Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
defer r.Body.Close()
switch r.URL.Path {
case "/handleA":
resp, err = svc.HandleA(r.Context(), req)
case "/handleB":
resp, err = svc.HandleB(r.Context(), req)
default:
http.NotFound(w, r)
return
}
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(resp)
})
})
}
在上面的示例代码中,我们注册了两个handler路由HandleA和HandleB,并使用switch语句来根据URL路径分发请求。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:关于go-zero单体服务使用泛型简化注册Handler路由的问题 - Python技术站