南京网站设计制作公司排名,小微企业名录,seo知名公司,百度金融1. 第一个Gin服务中的路由
我们的第一个gin服务源码如下#xff1a;
package mainimport (net/http// 导入gin框架github.com/gin-gonic/gin
)func main() {// 创建默认的gin路由router : gin.Default()// 定义一个简单的GET端点router.GET(/pi…1. 第一个Gin服务中的路由我们的第一个gin服务源码如下packagemainimport(net/http// 导入gin框架github.com/gin-gonic/gin)funcmain(){// 创建默认的gin路由router:gin.Default()// 定义一个简单的GET端点router.GET(/ping,func(c*gin.Context){// 返回JSON数据c.JSON(http.StatusOK,gin.H{message:pong,})})// 启动服务默认端口8080err:router.Run()iferr!nil{return}}代码中我们使用router.GET方法为我们的gin服务定义了一个简单的/ping路由。2. 设置路由Method除了GET方式的路由外Gin框架支持定义各种HTTP Method的路由2.1. GET、POST、PUT…Gin框架直接提供了大部分HTTP Method的路由定义方法GETPOSTPUTDELETEPATCHOPTIONSHEAD示例funcNewHttpRouter()*gin.Engine{router:gin.Default()router.GET(/ping,handler.GetPing)router.POST(/ping,handler.PostPing)router.PUT(/ping,handler.PutPing)router.DELETE(/ping,handler.DeletePing)router.PATCH(/ping,handler.PatchPing)router.OPTIONS(/ping,handler.OptionsPing)router.HEAD(/ping,handler.HeadPing)returnrouter}注意使用这些方法定义的路由只能使用对应的HTTP Method访问。如果使用错误的HTTP Method访问接口默认会404。2.2. 匹配所有MethodsAnyGin框架提供了Any方法来定义匹配所有HTTP Methods的路由。源码func(group*RouterGroup)Any(relativePathstring,handlers...HandlerFunc)IRoutes{// 可以看到实际上是为anyMethods中定义的所有HTTP Method都注册了路由for_,method:rangeanyMethods{group.handle(method,relativePath,handlers)}returngroup.returnObj()}示例funcNewHttpRouter()*gin.Engine{router:gin.Default()router.Any(/ping/any,handler.AnyPing)returnrouter}2.3. 更灵活的MethodHandleHandle方法以指定的路径和method注册路由。对于 GET、POST、PUT、PATCH 和 DELETE 请求可以使用相应的快捷函数。Handle方法旨在用于批量加载且它运行使用不常用的、非标准化的或者自定义的HTTP Method。Handle方法源码如下func(group*RouterGroup)Handle(httpMethod,relativePathstring,handlers...HandlerFunc)IRoutes{// 可以看到http method只做了简单的正则校验ifmatched:regEnLetter.MatchString(httpMethod);!matched{panic(http method httpMethod is not valid)}returngroup.handle(httpMethod,relativePath,handlers)}示例funcNewHttpRouter()*gin.Engine{router:gin.Default()// look这里的HTTP Method竟然是HELLOrouter.Handle(HELLO,/ping,handler.HelloPing)returnrouter}2.4. 匹配多种MethodsMatchMatch方法用于定义匹配多种HTTP Methods的路由。源码// 可以看到methods参数是一个数组func(group*RouterGroup)Match(methods[]string,relativePathstring,handlers...HandlerFunc)IRoutes{for_,method:rangemethods{group.handle(method,relativePath,handlers)}returngroup.returnObj()}示例funcNewHttpRouter()*gin.Engine{router:gin.Default()// 这里匹配GET和POSTrouter.Match([]string{GET,POST},/match,handler.MatchPing)returnrouter}2.5. MethodNotAllowed处理2.5.1. 默认行为404在上面的章节中我们介绍了各种定义路由HTTP Method的方式。当我们定义了一个路由应该使用的HTTP Method后如果请求的HTTP Method不匹配默认会应答404.示例router.GET(/ping,handler.GetPing)// 使用GET方式访问正常应答// 使用POST方式访问应答4042.5.2. HandleMethodNotAllowed配置gin.Engine中有一个HandleMethodNotAllowed属性可以用于修改Method不匹配时的默认行为。// HandleMethodNotAllowed if enabled, the router checks if another method is allowed for the// current route, if the current request can not be routed.// If this is the case, the request is answered with Method Not Allowed// and HTTP status code 405.// If no other Method is allowed, the request is delegated to the NotFound// handler.HandleMethodNotAllowedbool当HandleMethodNotAllowed开启时如果请求的路径存在但HTTP方法不匹配gin会检查该路径是否注册了其他HTTP方法。如果存在其他方法则返回405Method Not Allowed如果该路径没有任何方法注册则仍然返回404Not Found。示例router.HandleMethodNotAllowedtruerouter.GET(/ping,handler.GetPing)// GET方式访问/ping正常应答// POST方式访问/ping应答4052.5.3 自定义MethodNotAllowed处理上文提到如果请求路径正确但请求Method不匹配MethodNotAllowed场景如果HandleMethodNotAllowedfalse默认应答404Not Found。如果HandleMethodNotAllowedtrue默认应答405Method Not Allowed。除此之外gin还提供了NoMethod方法来自定义处理逻辑// 用于设置当 Engine.HandleMethodNotAllowed true 时调用的处理程序。func(engine*Engine)NoMethod(handlers...HandlerFunc){engine.noMethodhandlers engine.rebuild405Handlers()}示例funcNewHttpRouter()*gin.Engine{router:gin.Default()// 开启HandleMethodNotAllowedrouter.HandleMethodNotAllowedtruerouter.GET(/ping,handler.GetPing)// 定义处理函数router.NoMethod(handler.NoMethodPing)returnrouter}funcNoMethodPing(c*gin.Context){// 通常应返回405状态码但可根据需求自定义c.JSON(http.StatusMethodNotAllowed,gin.H{message:method not allowed,})}// GET方式访问/ping正常应答// POST方式访问/pingno method pong3. 路由组3.1. 路由组gin框架支持路由分组即将具有相同路径前缀或者需要相同中间件的路由放在同一个路由组中。Group方法用于路由分组其源码如下// Group creates a new router group. You should add all the routes that have common middlewares or the same path prefix.// For example, all the routes that use a common middleware for authorization could be grouped.func(group*RouterGroup)Group(relativePathstring,handlers...HandlerFunc)*RouterGroup{returnRouterGroup{Handlers:group.combineHandlers(handlers),basePath:group.calculateAbsolutePath(relativePath),engine:group.engine,}}Group方法用于创建一个新的路由组参数relativePath用于定义组中路由的通用路径。参数handlers用于定义组中路由的通用中间件。Group方法创建一个新的路由组我们可以将具有相同路径前缀或者要使用相同中间件的路由划分为一个组。示例funcNewHttpRouter()*gin.Engine{router:gin.Default()testRouter:router.Group(/test){testRouter.Any(/ping,handler.TestPing)testRouter.Any(/hello,handler.TestHello)}platRouter:router.Group(/plat,middleware.AuthMiddleware()){platRouter.Any(/login,handler.PlatLogin)platRouter.Any(/logout,handler.PlatLogout)}returnrouter}// 上面接口的访问路径分别为// /test/ping// /test/hello// /plat/login// /plat/logout3.2. 嵌套路由组Gin框架支持多级路由组嵌套允许更细粒度的路由组织。例如funcNewHttpRouter()*gin.Engine{router:gin.Default()api:router.Group(/api){v1:api.Group(/v1){v1.GET(/users,handler.GetUsers)v1.POST(/users,handler.CreateUser)}v2:api.Group(/v2){v2.GET(/users,handler.GetUsersV2)}}returnrouter}这样/api/v1/users和/api/v2/users将分别由不同的处理函数处理。此外父路由组的中间件会自动应用到所有子路由组。例如如果api组配置了认证中间件则v1和v2组的所有路由都将应用该中间件。4. 最佳实践在实际项目开发中合理使用Gin框架的路由和路由组功能能够大大提高代码的可维护性和可扩展性。以下是一些推荐的最佳实践4.1. 按业务模块划分路由组将不同业务模块的路由划分到不同的路由组中有助于保持代码结构清晰funcSetupRoutes(router*gin.Engine){// 用户相关路由userGroup:router.Group(/user){userGroup.POST(/register,user.Register)userGroup.POST(/login,user.Login)userGroup.GET(/profile,authMiddleware(),user.GetProfile)}// 订单相关路由orderGroup:router.Group(/order){orderGroup.GET(/:id,order.GetOrder)orderGroup.POST(/,authMiddleware(),order.CreateOrder)orderGroup.PUT(/:id,authMiddleware(),order.UpdateOrder)}// 管理后台路由adminGroup:router.Group(/admin,adminAuthMiddleware()){adminGroup.GET(/dashboard,admin.Dashboard)adminGroup.GET(/users,admin.ListUsers)adminGroup.DELETE(/users/:id,admin.DeleteUser)}}4.2. 合理使用中间件在路由组上应用共享的中间件避免重复代码// API版本控制v1:router.Group(/api/v1)v1.Use(loggingMiddleware(),corsMiddleware())authGroup:v1.Group(/auth)authGroup.Use(rateLimitMiddleware())// 特定路由组的额外中间件{authGroup.POST(/login,auth.Login)authGroup.POST(/register,auth.Register)}userGroup:v1.Group(/user,authRequiredMiddleware())// 需要认证的路由组{userGroup.GET(/profile,user.GetProfile)userGroup.PUT(/profile,user.UpdateProfile)}4.3. 统一错误处理通过NoRoute和NoMethod统一处理404和405错误funcSetupRouter()*gin.Engine{router:gin.Default()// 全局404处理router.NoRoute(func(c*gin.Context){c.JSON(http.StatusNotFound,gin.H{error:Page not found,path:c.Request.URL.Path,})})// 全局405处理router.HandleMethodNotAllowedtruerouter.NoMethod(func(c*gin.Context){c.JSON(http.StatusMethodNotAllowed,gin.H{error:Method not allowed,method:c.Request.Method,path:c.Request.URL.Path,})})// 路由定义...returnrouter}4.4. RESTful风格设计遵循RESTful API设计原则合理使用HTTP方法// 推荐的RESTful风格路由设计api:router.Group(/api/v1){// 资源集合操作api.GET(/posts,post.ListPosts)// 获取文章列表api.POST(/posts,post.CreatePost)// 创建新文章// 单个资源操作api.GET(/posts/:id,post.GetPost)// 获取特定文章api.PUT(/posts/:id,post.UpdatePost)// 完整更新文章api.PATCH(/posts/:id,post.PatchPost)// 部分更新文章api.DELETE(/posts/:id,post.DeletePost)// 删除文章// 子资源操作api.GET(/posts/:id/comments,comment.ListComments)// 获取文章评论api.POST(/posts/:id/comments,comment.CreateComment)// 添加评论}4.5. 路由版本控制通过路由组实现API版本控制funcSetupRoutes(router*gin.Engine){// v1版本APIv1:router.Group(/api/v1){v1.GET(/users,userHandler.ListUsersV1)v1.GET(/users/:id,userHandler.GetUserV1)}// v2版本APIv2:router.Group(/api/v2){v2.GET(/users,userHandler.ListUsersV2)v2.GET(/users/:id,userHandler.GetUserV2)v2.GET(/users/:id/profile,userHandler.GetUserProfileV2)}}4.6. 参数验证和路由分离将路由定义与业务逻辑分离使代码更加清晰// routes/setup.gofuncSetupUserRoutes(router*gin.Engine){userGroup:router.Group(/users){userGroup.GET(/,listUsers)userGroup.POST(/,createUser)userGroup.GET(/:id,getUser)userGroup.PUT(/:id,updateUser)userGroup.DELETE(/:id,deleteUser)}}// handlers/user_handler.gofunclistUsers(c*gin.Context){// 处理获取用户列表逻辑}funccreateUser(c*gin.Context){// 处理创建用户逻辑}funcgetUser(c*gin.Context){id:c.Param(id)// 处理获取单个用户逻辑}funcupdateUser(c*gin.Context){id:c.Param(id)// 处理更新用户逻辑}funcdeleteUser(c*gin.Context){id:c.Param(id)// 处理删除用户逻辑}