一. 路由组
- 什么是路由组: gin框架中通过路由组可以管理相同前缀的多个路由方法。方便进行统一的处理和管理
例如,可以将所有以/v1开头的路由归类到一个名为v1的路由组中,表示这些路由都是版本1的接口。也可以将所有以/admin开头的路由归类到一个名为authorized的路由组中,表示这些路由都需要身份验证。
- gin框架提供了r.Group(relativePath string, handlers …HandlerFunc)用于创建一个路由组。这个方法接受两个参数:relativePath表示路由组的相对路径,handlers表示可选的中间件函数
import (
"fmt"
"github.com/gin-gonic/gin"
"log"
"net/http"
)
func CreateRouter() *gin.Engine {
//获取默认RouterRouter
router := gin.Default()
//兜底的路由
router.NoRoute(errFunc)
//1.通过Router调用Grout("/")设置路由组
shopGroup := router.Group("/shop")
{
//2.通过路由组返回的*RouterGroup注册路由
shopGroup.GET("/index", func(c *gin.Context) {...})
shopGroup.GET("/cart", func(c *gin.Context) {...})
shopGroup.POST("/checkout", func(c *gin.Context) {...})
shopGroup.Post("/multFile",MultipartFuncs)
// 3.路由组中可以继续嵌套路由组
xx := shopGroup.Group("xx")
xx.GET("/oo", func(c *gin.Context) {...})
}
return router
}
- 我们也可以在创建路由组时传入一些中间件函数,它们会作用于该路由组下的所有路由
func main() {
r := gin.Default() // 创建一个默认的gin引擎
// 创建一个名为authorized的路由组,它的相对路径是/admin,并且使用AuthRequired中间件
authorized := r.Group("/admin", AuthRequired())
{
// 在authorized路由组下注册一个GET路由
authorized.GET("/dashboard", dashboardHandler)
}
r.Run(":8080") // 启动服务器
}
- 并且gin框架支持在一个路由组下创建子路由组,实现嵌套和继承的效果。子路由组会继承父路由组的相对路径和中间件,并且可以添加自己的相对路径和中间件。
二. 异步处理注意事项
- 解释,在请求后端接口时,某些情况下可能需要直接响应成功,后端异步去执行其他操作,此时直接通过groutine开启一个协程即可(接口默认是同步等待的),但是有几个注意点
- 在启动新的goroutine时,一定要使用c.Copy方法创建一个只读的上下文副本,否则可能会导致数据竞争或内存泄漏。
- 在异步处理完成后,如果想要返回响应,一定要使用r.HandleContext函数将请求转发到另一个路由函数,否则可能会导致响应头或响应体被写入多次或无法写入。
- 在异步处理中,如果需要访问数据库或外部服务,一定要使用合适的并发控制或连接池机制,否则可能会导致资源耗尽或性能下降。
- 在异步处理中,如果需要处理错误或异常情况,一定要使用合适的错误处理或恢复机制,否则可能会导致程序崩溃或数据丢失
Context.Copy
- 注意点,由于groutine是异步的,防止Context数据在groutine外部使用造成数据混乱所以在groutine中不可修改Context的值,通常情况下是复制一个Context的副本拿来使用
import (
"github.com/gin-gonic/gin"
"log"
"net/http"
"time"
)
func main() {
r := gin.Default()
//1. 注册路由(默认同步的)
r.GET("/long_sync", func(c *gin.Context) {
time.Sleep(5 * time.Second)
// 注意可以使⽤原始上下⽂
log.Println("Done! in path " + c.Request.URL.Path)
})
//1. 异步,在AsyncTest函数中直接响应结果,然后通过goroutine异步执行,
r.GET("/long_async", AsyncTest)
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
func AsyncTest(c *gin.Context) {
//1.复制出一份只读的Context供goroutine中使⽤
cCp := c.Copy()
//2.开启goroutine异步执行逻辑
go func() {
time.Sleep(5 * time.Second)
// 注意使⽤只读上下⽂
log.Println("Done! in path " + cCp.Request.URL.Path)
}()
//此处直接响应
c.JSON(http.StatusOK, gin.H{"data": "成功响应的数据"})
}