在gin框架中,所有的路由都是通过IRoutes接口中的Handle方法进行处理的。在我们使用gin的路由之前,非常有必要了解这个方法的定义和参数用法。因为gin支持的9种请求方式(GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, CONNECT, TRACE)都是通过该方法来完成的。
路由处理方法Handle 详解
这个方法就是用来处理http请求方法,路由地址和对应的路由处理控制器的。
方法定义: Handle(string, string, ...HandlerFunc) IRoutes
第一个参数 就是请求方式字符串,支持GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, CONNECT, TRACE 这9种请求方式,注意请求方式字符串必须是大写!
第二个参数 是路由地址字符串,即用户可通过这个地址访问到相关的控制器
第三个参数HandlerFunc 这个参数是一个可变参数,他是对应的路由地址的处理控制器,可以是多个控制器,即一个路由地址可以同时转发到多个后端控制器处理。 HandlerFunc是一个函数类型,这个函数类型的定义为: type HandlerFunc func(*Context) 这个的意思就是只要是你的函数/方法的入参只有一个且是 *gin.Context 类型就可以作为路由的处理控制器函数。
注意,理解这个 路由处理函数 HandlerFunc 对于使用gin框架非常重要!!! 因为gin中的所有的路由、 中间件的入参都必须要符合这个HandlerFunc的定义! 即 只能有一个*gin.Context 类型的参数。
gin中间件
gin框架中的中间件,实际上就是一个符合HandlerFunc函数定义的函数/方法,即函数/方法的参数类型必须是 *gin.Context 且只能有一个参数,没有返回值。 在中间件中我们使用 c.Next() 方法来继续后续的处理, 如果要在中间件中拦截当前请求, 需要使用 c.Abort() 中断后续请求,和return返回当前请求来立即中断网络请求。
使用方法参考 : 用于gin框架的CORS中间件,解决身份凭证和通配符不能同时设置问题,可同时配置附带身份凭证的请求和*通配符,chrome插件CORS跨域请求通配符-CSDN博客
GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS请求方式使用方法
gin框架中支持的9种请求方式,GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, 这7种请求方式gin框架在IRoutes接口中都为我们定义了相应的快捷方式方法, 即
使用方法就是直接通过路由对象 r.XXX() 来使用,示例:
func main() {
r := gin.Default()
// GET请求, 支持的7种请求,可选项有 GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
r.GET("/index", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "Hello world!",
})
})
r.Run(":8080")
}
CONNECT, TRACE 请求方式使用方法
对于这2种请求方式,gin框架没有提供相应的快捷方法,我们可以直接通过路由对象中的 Handle方法来实现。 使用示例:
// 定义一个HandlerFunc路由处理函数 注意这里的入参只能有1个且必须是 *gin.Context
handlerFn := func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"msg": "Hello world!",
})
}
// Handle路由处理方法使用示例
r.Handle("CONNECT", "/index", handlerFn)
Any方法
gin路由接口中的Any方法在内部实际上是gin框架帮我们一起注册了全部的9个请求类型的路由到你指定的路由地址和控制器上面。参数和前面的7种请求方式是一样的,第一个参数是路由地址,第二个参数是路由处理控制器方法/函数。
Any方法源码参考:
// Any registers a route that matches all the HTTP methods.
// GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE, CONNECT, TRACE.
func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) IRoutes {
for _, method := range anyMethods {
group.handle(method, relativePath, handlers)
}
return group.returnObj()
}
上面的anyMethods这个变量的定义为:
anyMethods = []string{
http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch,
http.MethodHead, http.MethodOptions, http.MethodDelete, http.MethodConnect,
http.MethodTrace,
}
这里实际上就是go语言中http所支持的9种请求方式的常量,位于go内置包 "net/http" 中。
Match方法
这个方法实际上就是Any犯法的优化版本。他比Any方法多了一个参数,这个参数用于定义我们需要注册的方法路由。
Match方法定义参考:
// Match registers a route that matches the specified methods that you declared.
func (group *RouterGroup) Match(methods []string, relativePath string, handlers ...HandlerFunc) IRoutes {
for _, method := range methods {
group.handle(method, relativePath, handlers)
}
return group.returnObj()
}
这里的第一个参数 methods是一个字符串切片,这个切片即我们要注册的请求方法,他们的值只能是 上面的9种请求方法中的一个或者多个。
// Match路由处理方法使用示例
r.Match([]string{"GET", "POST", "PUT", "DELETE", "HEAD"},"/index", handlerFn)
上面的示例会对路由地址 /index 一次性注册"GET", "POST", "PUT", "DELETE", "HEAD" 这5个请求方法对应的路由到handlerFn函数。
gin框架路由接口定义参考
// IRoutes defines all router handle interface.
type IRoutes interface {
Use(...HandlerFunc) IRoutes
Handle(string, string, ...HandlerFunc) IRoutes
Any(string, ...HandlerFunc) IRoutes
GET(string, ...HandlerFunc) IRoutes
POST(string, ...HandlerFunc) IRoutes
DELETE(string, ...HandlerFunc) IRoutes
PATCH(string, ...HandlerFunc) IRoutes
PUT(string, ...HandlerFunc) IRoutes
OPTIONS(string, ...HandlerFunc) IRoutes
HEAD(string, ...HandlerFunc) IRoutes
Match([]string, string, ...HandlerFunc) IRoutes
StaticFile(string, string) IRoutes
StaticFileFS(string, string, http.FileSystem) IRoutes
Static(string, string) IRoutes
StaticFS(string, http.FileSystem) IRoutes
}
Static X方法
路由接口中的最后这4个static x方法是用来处理静态文件的,他们的功能都一样,只是入参不一样而已。 他们的第一个参数relativePath就是静态资源的路由地址,后面的参数是不同类型的静态资源。 对于静态资源的处理,gin框架自动帮我们注册了2个请求方式,即 GET 用于静态资源的浏览查看, HEAD 用于获取静态资源的头信息 。
使用示例:r.Static("/static", "public/static")
方法参考
// Static serves files from the given file system root.
// Internally a http.FileServer is used, therefore http.NotFound is used instead
// of the Router's NotFound handler.
// To use the operating system's file system implementation,
// use :
//
// router.Static("/static", "/var/www")
func (group *RouterGroup) Static(relativePath, root string) IRoutes {
return group.StaticFS(relativePath, Dir(root, false))
}
// StaticFS works just like `Static()` but a custom `http.FileSystem` can be used instead.
// Gin by default uses: gin.Dir()
func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) IRoutes {
if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
panic("URL parameters can not be used when serving a static folder")
}
handler := group.createStaticHandler(relativePath, fs)
urlPattern := path.Join(relativePath, "/*filepath")
// Register GET and HEAD handlers
group.GET(urlPattern, handler)
group.HEAD(urlPattern, handler)
return group.returnObj()
}
func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc {
absolutePath := group.calculateAbsolutePath(relativePath)
fileServer := http.StripPrefix(absolutePath, http.FileServer(fs))
return func(c *Context) {
if _, noListing := fs.(*onlyFilesFS); noListing {
c.Writer.WriteHeader(http.StatusNotFound)
}
file := c.Param("filepath")
// Check if file exists and/or if we have permission to access it
f, err := fs.Open(file)
if err != nil {
c.Writer.WriteHeader(http.StatusNotFound)
c.handlers = group.engine.noRoute
// Reset index
c.index = -1
return
}
f.Close()
fileServer.ServeHTTP(c.Writer, c.Request)
}
}
总结: gin框架的路由支持GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, CONNECT, TRACE这9种请求方式, 请求方式名称必须是大写, 这9种请求方式在gin内部都是通过handle方法来处理, gin框架中的路由处理函数和中间件的定义实际上就是定义一个入参类型为 *gin.Context 的函数或者方法。 gin在中间件中通过调用 gin.Context对象中的.Next()方法来继续处理后续请求,通过调用 .Abort() 方法来中断后续请求,通过使用return语句来立刻中断当前函数/方法的请求。