Go笔记-day9 | 青训营

180 阅读6分钟

本示例主要介绍了在Gin框架中使用中间件、路由组以及文件上传的操作。

对于中间件的使用,可以通过定义函数作为中间件来对请求进行处理。示例中给出了一个计时中间件m1,用于统计请求处理函数的耗时。在中间件函数中,使用c.Next()调用后续的处理函数,然后计算耗时并输出。可以通过全局注册中间件函数r.Use(m1)来应用到所有的请求中。

另外,Gin中还提供了路由组的概念,可以将共用的前缀提取出来创建一个路由组。示例代码给出了一个路由组的定义,该路由组的前缀为"/feed",其中定义了多个与视频和商城相关的路由处理函数。通过这种方式可以更好地组织和管理路由。

对于文件上传,在示例代码中,定义了一个POST类型的/upload路由,用于接收客户端上传的文件。通过c.FormFile("f1")获取请求中的文件,然后将文件保存在服务端本地。在示例中,使用了c.SaveUploadedFile函数将文件保存到指定路径。

最后,还介绍了一些其他的功能,比如重定向、错误处理和静态文件服务等。重定向可以使用c.Redirect实现,示例中给出了一个在/index路由中执行重定向的示例。对于没有匹配到路由的请求,可以使用r.NoRoute定义一个默认的处理函数,示例中给出了一个返回404状态码的示例。静态文件服务可以使用r.Static和r.StaticFile函数实现,用于提供静态资源的访问。

总的来说,Gin框架提供了丰富的功能和中间件支持,可以方便地进行路由管理、中间件处理、文件上传等操作,帮助开发者快速构建Web应用程序。

Gin中间件是在请求被处理之前或之后执行的函数。它可以用于在请求到达处理函数之前进行一些预处理操作,或在处理函数执行完成后进行后续处理。

在Gin中,中间件函数的签名是func(c *gin.Context),其中c *gin.Context代表当前请求的上下文对象,您可以通过它访问请求和响应的相关信息。

Gin中间件的使用非常灵活,可以按需在全局范围或特定路由范围内应用中间件。以下是几种常见的中间件用法:

  1. 全局中间件:使用r.Use()方法将中间件函数注册为全局中间件。这样,所有的请求都会经过这个中间件的处理。例如,r.Use(LoggerMiddleware)可以在每个请求中记录日志。
  2. 路由组中间件:使用Group方法创建一个带有共享中间件的路由组。中间件函数将只对该路由组中的请求生效。例如,vGroup := r.Group("/videos", AuthMiddleware)可以为与视频相关的路由应用认证中间件。
  3. 单个路由中间件:在定义单个路由时,可以通过链式调用的方式应用中间件。例如,r.GET("/profile", AuthMiddleware, ProfileHandler)可以在访问/profile路由时应用认证中间件。

中间件可以实现诸如身份验证、授权、日志记录、性能监控等功能。除了在中间件函数中进行处理,还可以使用c.Get()c.Set()方法在上下文中传递数据,使不同的中间件之间可以共享信息。

需要注意的是,如果在中间件函数中调用了c.Abort(),则会阻止后续中间件和处理函数的执行,并直接返回响应。这在进行权限验证或错误处理时非常有用。

当然,我会继续为您解释有关Gin中间件的更多细节。

在Gin框架中,中间件可以按照注册顺序依次执行。下面是一些关于Gin中间件的重要概念和用法:

  1. 中间件链:可以使用多个中间件来构建中间件链。Gin通过将中间件函数传递给UseGroup方法来创建中间件链。例如: go r.Use(Middleware1, Middleware2, Middleware3)

这样,每个请求都会依次经过Middleware1、Middleware2和Middleware3。当一个中间件函数调用c.Next()时,控制流会转移到下一个中间件或处理函数;而如果没有调用c.Next(),则控制流会直接返回。

  1. 处理函数前置中间件:您可以使用处理函数前置中间件来在处理函数执行之前进行一些预处理。例如,身份验证和权限检查通常在处理函数之前进行。
  2. 处理函数后置中间件:您还可以使用处理函数后置中间件来在处理函数执行完成后进行一些后续处理。例如,日志记录和性能监控通常在处理函数之后进行。

总的来说,Gin中间件提供了一种灵活且可扩展的方式来处理请求的预处理和后处理。通过使用适当的中间件,您可以轻松地添加各种功能和逻辑到您的应用程序中。

如果您有任何其他问题,随时提问!

# Gin URL请求的重定向 + Gin路由和路由组

package main
 
import (
	"github.com/gin-gonic/gin"
	"net/http"
)
 
func main() {
	r := gin.Default()
	r.GET("/index", func(c *gin.Context) {
		c.Redirect(http.StatusMovedPermanently, "")
	})
 
	r.GET("/a", func(c *gin.Context) {
		//跳转到b对应的路由处理函数
		c.Request.URL.Path = "/b" //修改请求的URL的path
		r.HandleContext(c)
	})
 
	r.GET("/b", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"message": "b",
		})
	})
 
	r.Run(":9090")
}

Gin中使用r.Any()可以匹配任意请求,比如常用的GET--获取 POST--提交 PUT--更新 DELTE--删除 MethodGet = "GET" MethodHead = "HEAD" MethodPost = "POST" MethodPut = "PUT" MethodPatch = "PATCH" // RFC 5789 MethodDelete = "DELETE" MethodConnect = "CONNECT" MethodOptions = "OPTIONS" MethodTrace = "TRACE" 为没有配置处理函数的路由添加处理程序,默认情况下它返回404代码,下面的代码为没有匹配到路由的请求返回页面

	r.NoRoute(func(c *gin.Context) {
		c.JSON(http.StatusNotFound, gin.H{
			"msg": "无法找到",
		})
	})

//路由组的组 //把共用的前缀提取出来,创建一个路由组

v_grop := r.Group("/feed")

package main
 
import (
	"github.com/gin-gonic/gin"
	"net/http"
)
 
func main() {
	r := gin.Default()
	r.GET("/index", func(c *gin.Context) {
 
	})
	r.NoRoute(func(c *gin.Context) {
		c.JSON(http.StatusNotFound, gin.H{
			"msg": "无法找到",
		})
	})
 
	//路由组的组
	//把共用的前缀提取出来,创建一个路由组
	v_grop := r.Group("/feed")
	{
		//视频的首页和详情页
		v_grop.GET("/video", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{
				"msg": "视频",
			})
		})
		//商城的首页和详情页
		//...
	}
	r.Run(":9090")
}

Gin中间件

洋葱模型

一般的中间件如下:

// 校验登录的逻辑
func outhmiddleware(doCheck bool) gin.HandlerFunc { //传入的参数是开关
	//连接数据库  做一些其他操作
 
	return func(c *gin.Context) { //通过包装一层的闭包
		if doCheck {
			//是否登录
			//if 是登录用户
			c.Next()
			//else
			c.Abort()
		} else { //放行
			c.Abort()
		}
	}
}

路由组也是可以进行定义中间件的,两种写法:

shopGroup := r.Group("/shop", StatCost())
{
    shopGroup.GET("/index", func(c *gin.Context) {...})
    ...
}
shopGroup := r.Group("/shop")
shopGroup.Use(StatCost())
{
    shopGroup.GET("/index", func(c *gin.Context) {...})
    ...
}

中间件代码实例如下:

package main
 
import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"time"
)
 
// 定义一个中间件m1:统计请求处理函数的耗时
func m1(c *gin.Context) {
	fmt.Println("m1 in ...")
	//计时
	start := time.Now()
	c.Next() //调用后续的处理函数
	//c.Abort() 阻止调用后续的处理函数
	cost := time.Since(start) //start到现在经过的时间
	fmt.Printf("cost:%#v\n", cost)
	fmt.Println("m1 out ...")
}
 
func m2(c *gin.Context) {
	fmt.Println("m2 in ...")
	c.JSON(http.StatusOK, gin.H{
		"msg": "ok",
	})
	fmt.Println("m2 out ...")
}
 
func index(c *gin.Context) {
	c.JSON(200, gin.H{
		"msg": "index",
	})
}
 
func main() {
	r := gin.Default()
	r.Use(m1) //全局注册中间件函数m1
	r.GET("/", m2)
	r.GET("/index", index)
	r.Run(":9090")
}

c.Get() c.Set()可以实现从上下文中取值(跨中间件存取值)

r:=gin.Default() 默认使用Logger()-记录日志 和Recover()-返回panic --500响应码 不至于网站会直接挂掉 中间件,使用gin.New()零中间件

在中间件中进行协程,只能进行如下:

go funcXX(c.Copy()) 不能修改c,因为会导致c.Next()后面的c获取的内容是不可控的