为了简化路由注册方式,避免一些繁琐的参数处理细节, 让开发者将精力聚焦于业务逻辑本身,GoFrame框架提供了规范化的路由注册方式。 规范化的路由注册方式,我们为了见名知意,便命名为了规范路由

数据结构定义

在规范路由中,我们同样定义一个请求的数据结构来接收客户端提交的参数信息,但同时需要定义一个返回对象。 目的是为了未来返回参数扩展的需要,以及未来标准化接口文档生成的需要。

  1. type HelloReq struct {
  2. g.Meta `path:"/" method:"get"`
  3. Name string `v:"required" dc:"姓名"`
  4. Age int `v:"required" dc:"年龄"`
  5. }
  6. type HelloRes struct {}

简要介绍:

  • 在请求对象中,我们多了一个g.Meta对象的引用,并给定了一些结构体标签。该对象为元数据对象,用于给结构体嵌入 一些定义的标签信息。例如在本示例中:
    • path:表示注册的路由地址。
    • method:表示注册绑定的HTTP Method
  • 在属性中同样出现两个新的标签名称:
    • v:表示校验规则,为valid的缩写,用于自动校验该参数。这里使用v:"required"表示该参数为必需参数,如果客户端未传递该参数时,服务端将会校验失败。
    • dc:表示参数描述信息,为description的缩写,用于描述该参数的含义。

使用规范路由 - 图1信息

在开发手册的对应章节中,有关于全部标签信息以及校验组件的详细讲解,这里只需要了解其作用即可,不做过多介绍。

路由对象管理

为了更好地管理路由注册,特别是接口比较多的场景下,如果手动一一去配置路由与回调函数关系太过于繁琐。 我们通过对象化的形式来封装路由回调函数,通过对象化封装的方式来简化我们的路由管理。 我们定义一个路由对象如下:

  1. type Hello struct{}
  2. func (Hello) Say(ctx context.Context, req *HelloReq) (res *HelloRes, err error) {
  3. r := g.RequestFromCtx(ctx)
  4. r.Response.Writef(
  5. "Hello %s! Your Age is %d",
  6. req.Name,
  7. req.Age,
  8. )
  9. return
  10. }
  • 我们定义了一个Hello对象,该对象用于封装路由回调函数,其所有定义的公开方法都将被作为路由回调函数进行注册。
  • 可以看到该路由对象的Say方法的回调函数的定义方式,相比较于func(*ghttp.Request)的回调函数定义方式,更符合业务逻辑函数的定义风格。
  • 在路由回调方法Say中,我们通过g.RequestFromCtx方法从ctx获取原始的*ghttp.Request请求对象,用于自定义返回内容数据。

完整示例代码

我们调整我们前面的Web Server程序如下:

main.go

  1. package main
  2. import (
  3. "context"
  4. "github.com/gogf/gf/v2/frame/g"
  5. "github.com/gogf/gf/v2/net/ghttp"
  6. )
  7. type HelloReq struct {
  8. g.Meta `path:"/" method:"get"`
  9. Name string `v:"required" dc:"姓名"`
  10. Age int `v:"required" dc:"年龄"`
  11. }
  12. type HelloRes struct{}
  13. type Hello struct{}
  14. func (Hello) Say(ctx context.Context, req *HelloReq) (res *HelloRes, err error) {
  15. r := g.RequestFromCtx(ctx)
  16. r.Response.Writef(
  17. "Hello %s! Your Age is %d",
  18. req.Name,
  19. req.Age,
  20. )
  21. return
  22. }
  23. func main() {
  24. s := g.Server()
  25. s.Group("/", func(group *ghttp.RouterGroup) {
  26. group.Bind(
  27. new(Hello),
  28. )
  29. })
  30. s.SetPort(8000)
  31. s.Run()
  32. }

在本示例中:

  • 通过s.Group的分组路由方式定义一组路由注册,在其回调方法中注册的所有路由,都会带有其定义的分组路由前缀/
  • 通过group.Bind方法注册路由对象,该方法将会遍历路由对象的所有公开方法,读取方法的输入输出结构体定义,并对其执行路由注册。

执行结果

运行后,我们访问 http://127.0.0.1:8000/?name=john&age=18 可以看到,页面输出结果符合预期。

img.png

我们尝试一下错误的参数请求 http://127.0.0.1:8000/ 但我们发现,页面没有输出任何的结果? 这是由于参数校验失败,并未进入到我们的路由回调函数中,而是被Server直接返回了。

学习小结

在本章节我们学会了规范的路由注册方式,但是还缺少对返回结果,特别是产生错误之后的统一处理控制。

那么,我们应该如何捕获校验失败错误并自定义返回数据呢?我们将在下一章节更进一步介绍。