Gin第四天---路由注册

简介: Gin第四天---路由注册

Gin第四天


1. 路由组


当我们有许多相同的URL,但是需要它们处理不同的请求,这个时候就可以利用路由组来分别设置。


例如把GET请求的路由放在一个分组里,把POST请求的分组放在另一个。


package main
import (
   "fmt"
   "github.com/gin-gonic/gin"
   "net/http"
)
func main(){
   r:=gin.Default()
   v1:=r.Group("/get")
   {
      v1.GET("/login",login)
      v1.GET("/submit",submit)
   }
   v2:=r.Group("/post")
   {
      v2.POST("/login",login)
      v2.POST("/submit",submit)
   }
   r.Run()
}
func login(c *gin.Context){
   name:=c.DefaultQuery("name","shelgi")
   c.String(http.StatusOK,fmt.Sprintf("hello %s\n",name))
}
func submit(c *gin.Context){
   name:=c.DefaultQuery("name","shelgi")
   c.String(http.StatusOK,fmt.Sprintf("hello %s\n",name))
}
复制代码



image.png

image.png

image.png

但如果我们用post请求去请求get操作对应的页面,就会返回404

image.png


来看看Group到底干了什么,它是RouterGroup的一个方法,然后内部将传入的相对路径转换为绝对路径,并且把处理函数结合起来(下图二),返回一个路由组

image.pngimage.png

可以看到这里对传入的处理函数有规模限制,这里面abortIndex从源码可以看到

const abortIndex int8=math.MaxInt8 / 2


也就是总共的处理函数不能超过63个


关于Gin的路由原理,涉及到前缀树和基数树,基数树就是前缀树压缩优化后的结果;Gin采用httprouter进行路由匹配,每个http方法对应都会生成一颗基数树,下面是树节点的结构


image.png


里面包含了路径、索引、前节点、孩子节点、处理函数链……

感兴趣的可以去gin源码中的tree.go看看实现


2. 路由的拆分与注册


2.1 基本的路由注册


最基本的路由注册就是先写一个处理函数,然后再将这个处理函数与请求方法与路由路径绑定上,类似于下面的例子


package main
import (
   "github.com/gin-gonic/gin"
   "net/http"
)
func testhandler(c *gin.Context){
   c.JSON(http.StatusOK,gin.H{
      "test":"这是路由注册的测试",
   })
}
func main(){
   r:=gin.Default()
   r.GET("/test",testhandler)
   r.Run()
}


image.png

2.2 路由拆分为包


当我们需要处理注册的路由数量过多时,全部写在一个文件里既不方便阅读修改,也不能很好的简化代码结构,为此我们可以把这部分代码拎出来单独作为一个包

创建一个routers的包,然后将路由注册部分全部放在这个包里


package routers
import (
   "github.com/gin-gonic/gin"
   "net/http"
)
func testhandler(c *gin.Context){
   c.JSON(http.StatusOK,gin.H{
      "test":"这是路由注册的测试",
   })
}
func SetupRouter() *gin.Engine{
   r:=gin.Default()
   r.GET("/test",testhandler)
   return r
}
复制代码


然后在主函数中引入已经实例化路由注册后的引擎


package main
import (
   "Learn_Gin/Gin-day4/routers"
)
//从Routers包中引入路由
func main() {
   r := routers.SetupRouter()
   r.Run()
}
复制代码


image.png


2.3 路由拆分为多个文件


我们现在是把所有的路由注册全部写在SetupRouter中,但是如果我们的路由更多,同样会引起之前一样的问题,所以我们还可以继续分,分为更细致的模块化


在routers中创建两个路由,传入引擎实例作为参数,在模块中就实现了各个路由的注册


package routers
import (
   "github.com/gin-gonic/gin"
   "net/http"
)
func test1handler(c *gin.Context){
   c.JSON(http.StatusOK,gin.H{
      "test":"这是路由1注册的测试",
   })
}
func Test1(e *gin.Engine){
   e.GET("/test1",test1handler)
}
复制代码
package routers
import (
   "github.com/gin-gonic/gin"
   "net/http"
)
func test2handler(c *gin.Context){
   c.JSON(http.StatusOK,gin.H{
      "test":"这是路由2注册的测试",
   })
}
func Test2(e *gin.Engine){
   e.GET("/test2",test2handler)
}
复制代码


在主函数中只用调用这两个函数就可以啦


package main
import (
   "Learn_Gin/Gin-day4/routers"
   "github.com/gin-gonic/gin"
)
//多文件路由注册
func main(){
   r:=gin.Default()
   routers.Test1(r)
   routers.Test2(r)
   r.Run()
}
复制代码


image.png

image.png]

说到这里,来互相对比一下。拿我们熟悉的Flask作为对比,除了@app.route("/") 装饰器方式注册路由,还可以使用app.add_url_rule(rule="xxx",view_func=func)

这个和我们的r.GET(relativePath="/",handles)结构上其实是一样的,有的时候交叉对比学习,可以进行知识迁移,从而更简单的理解使用


2.4 路由拆分为多个APP


当我们的项目继续扩大,全部放在routers里面还是不能满足分模块的效果,我们就可以继续再分;每个不同的功能模块放在APP的不同模块下,然后在各自的模块中实现handler和Routers(路由注册),最终只需要在routers中将所有APP注册的路由全部整合在一起(一个切片中),然后初始化方法中用实例一个个遍历注册。在主函数中只需要直接初始化然后运行就可以了。


APP/demo/下


package demo
import (
   "github.com/gin-gonic/gin"
   "net/http"
)
func idHandler(c *gin.Context){
   c.JSON(http.StatusOK,gin.H{
      "id_test":"这是id的测试",
   })
}
func commentHandler(c *gin.Context){
   c.JSON(http.StatusOK,gin.H{
      "comment_test":"这是comment的测试",
   })
}
复制代码
package demo
import "github.com/gin-gonic/gin"
func Routers(e *gin.Engine) {
   e.GET("/id", idHandler)
   e.GET("/comment", commentHandler)
}
复制代码

routers中合并注册整合,然后同意初始化


package routers
import "github.com/gin-gonic/gin"
type Option func(*gin.Engine)
var options = []Option{}
// 注册app的路由配置
func Include(opts ...Option) {
   options = append(options, opts...)
}
// 初始化
func Init() *gin.Engine {
   r := gin.New()
   for _, opt := range options {
      opt(r)
   }
   return r
}
复制代码


主函数中调用整合初始化方法,直接启动


package main
import (
   "Learn_Gin/Gin-day4/APP/demo"
   "Learn_Gin/Gin-day4/routers"
)
func main(){
   routers.Include(demo.Routers)
   r:=routers.Init()
   r.Run()
}


image.png

总结


这部分主要就是在处理一件事,如何解耦,使各个模块之间更细分并且在项目方便使用。不论是从项目的目录结构还是从代码功能都能让人比较清晰直观的理解,这样的项目不仅利于开发,更利于后期的迭代更新、运营维护。

目录
相关文章
|
存储 中间件 测试技术
gin 路由注册源码分析
Gin 是一个用 Go (Golang) 编写的 HTTP Web 框架。 它具有类似 Martini 的 API,但性能比 Martini 快 40 倍。如果你需要极好的性能,使用 Gin 吧。
|
6月前
|
前端开发 JavaScript 关系型数据库
若依框架------后台路由数据是如何转换为前端路由信息的
若依框架------后台路由数据是如何转换为前端路由信息的
579 0
|
29天前
|
前端开发 网络协议
Nest.js 实战 (十四):如何获取客户端真实 IP
这篇文章介绍了在Nest.js应用中获取客户端真实IP地址的问题及解决方法。问题出现在使用本地代理时,请求的IP地址总是返回::1或::ffff:127.0.0.1。为解决这个问题,需要确保代理服务器正确设置转发头如X-Forwarded-For或X-Real-IP,后端服务能够读取这些头信息来确定客户端的IP地址。文章以作者自己的OpenResty应用为例,展示了如何通过配置反向代理和设置X-Forwarded-For头来获取真实IP地址,并提供了相关的代码示例。最后,文章提到了使用这个解决方案后的实际效果,例如在操作日志中记录真实IP地址。
|
5月前
|
JavaScript
vue路由从入门到进阶 --- 路由重定向与404等问题
vue路由从入门到进阶 --- 路由重定向与404等问题
|
5月前
|
缓存 网络协议 搜索推荐
gin框架学习笔记(三) ——路由请求与相关参数
gin框架学习笔记(三) ——路由请求与相关参数
|
XML JSON 程序员
Day04:Gin框架快速入门03 bind绑定器| 青训营(一)
Day04:Gin框架快速入门03 bind绑定器| 青训营
|
前端开发
Day04:Gin框架快速入门03 bind绑定器| 青训营(二)
Day04:Gin框架快速入门03 bind绑定器| 青训营
|
前端开发 Java
【React工作记录九十七】前后端springboot+vue+实现部门的增删改功能记录
【React工作记录九十七】前后端springboot+vue+实现部门的增删改功能记录
60 0
|
中间件 开发者
gin框架学习-路由分组和中间件
Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release。
365 5
gin框架学习-路由分组和中间件
|
前端开发
【React工作记录六十三】Http常见错误
【React工作记录六十三】Http常见错误
107 0