Go-web(二)异步请求

Go-web(二)异步请求

异步请求

goroutine机制可以方便地实现异步处理,另外,在启动新的goroutine时,不应该使用原始上下文,必须使用它的只读副本。

	// 异步处理请求
	r.GET("/async", func(context *gin.Context) {
		// copy请求
		copyContext := context.Copy()
		go func() {
			time.Sleep(3 * time.Second)
			fmt.Println("异步执行:",copyContext.Request.URL.Path)
		}()
		context.JSON(200,"执行成功")
	})
	r.Run(":8080")

请求后,会立马返回执行成功,异步操作执行完成后,会返回请求url路径。

重定向

	r.GET("/redict", func(context *gin.Context) {
		context.Redirect(302,"/async")
	})

中间件

gin中的中间件是一个http请求的拦截器。

定义中间件:

// 编写一个返回值是HandlerFunc的方法即可
func Mid1() gin.HandlerFunc {
	return func(context *gin.Context) {
		fmt.Println("mid1 start")
		//context.Next()
		fmt.Println("mid1 end")
	}
}

HandlerFunc是gin中自定义的类型:

type HandlerFunc func(*Context)

注册中间件:

	// 注册全局中间件
	r.Use(Mid1(),Mid2(),Mid3())

看一个demo:

注册三个中间件,都不调用Next方法:

	// 注册全局中间件
	r.Use(Mid1(),Mid2(),Mid3())
	r.GET("/useMid", func(context *gin.Context) {
		fmt.Println(".... request start ....")
		time.Sleep(3 * time.Second)
		fmt.Println(".... request end ....")
		context.JSON(200,"")
	})

func Mid1() gin.HandlerFunc {
	return func(context *gin.Context) {
		fmt.Println("mid1 start")
		//context.Next()
		fmt.Println("mid1 end")
	}
}
func Mid2() gin.HandlerFunc {
	return func(context *gin.Context) {
		fmt.Println("mid2 start")
		//context.Next()
		fmt.Println("mid2 end")
	}
}
func Mid3() gin.HandlerFunc {
	return func(context *gin.Context) {
		fmt.Println("mid3 start")
		//context.Next()
		fmt.Println("mid3 end")
	}
}

执行结果:

在这里插入图片描述

不调用Next方法,中间件会按照注册的顺序执行,最后执行请求。可以用来做一些前置处理,如鉴权限流啥的

在这里插入图片描述

在看一个调用Next方法的:

	// 注册全局中间件
	r.Use(Mid1(),Mid2(),Mid3())
	r.GET("/useMid", func(context *gin.Context) {
		fmt.Println(".... request start ....")
		time.Sleep(3 * time.Second)
		fmt.Println(".... request end ....")
		context.JSON(200,"")
	})

func Mid1() gin.HandlerFunc {
	return func(context *gin.Context) {
		fmt.Println("mid1 start")
		context.Next()
		fmt.Println("mid1 end")
	}
}
func Mid2() gin.HandlerFunc {
	return func(context *gin.Context) {
		fmt.Println("mid2 start")
		context.Next()
		fmt.Println("mid2 end")
	}
}
func Mid3() gin.HandlerFunc {
	return func(context *gin.Context) {
		fmt.Println("mid3 start")
		context.Next()
		fmt.Println("mid3 end")
	}
}

执行结果:

在这里插入图片描述

程序会在调用Next方法地方执行下一个中间件,并且执行顺序是按照中间件的注册顺序。实际执行的请求可以理解为一个默认的中间件。

在这里插入图片描述

如果一个中间件调用了Abort方法:

	// 注册全局中间件
	r.Use(Mid1(),Mid2(),Mid3())
	r.GET("/useMid", func(context *gin.Context) {
		fmt.Println(".... request start ....")
		time.Sleep(3 * time.Second)
		fmt.Println(".... request end ....")
		context.JSON(200,"")
	})

func Mid1() gin.HandlerFunc {
	return func(context *gin.Context) {
		fmt.Println("mid1 start")
		context.Next()
		fmt.Println("mid1 end")
	}
}
func Mid2() gin.HandlerFunc {
	return func(context *gin.Context) {
		fmt.Println("mid2 start")
		context.Abort()
		fmt.Println("mid2 end")
	}
}
func Mid3() gin.HandlerFunc {
	return func(context *gin.Context) {
		fmt.Println("mid3 start")
		context.Next()
		fmt.Println("mid3 end")
	}
}

结果:

在这里插入图片描述

后续的请求和中间件都不会执行。

所以:如果某个中间件调用了c.Abort(),则此中间件结束后会直接返回,后面的中间件均不会调用。

gin默认注册了日志中间件Logger()和异常捕获中间件Recovery()

Logger()

func Logger() HandlerFunc {
	return LoggerWithConfig(LoggerConfig{})
}

Recovery()

func Recovery() HandlerFunc {
	return RecoveryWithWriter(DefaultErrorWriter)
}

底层就是通过recover()方法捕获panic做处理:

func CustomRecoveryWithWriter(out io.Writer, handle RecoveryFunc) HandlerFunc {
	var logger *log.Logger
	if out != nil {
		logger = log.New(out, "\n\n\x1b[31m", log.LstdFlags)
	}
	return func(c *Context) {
		defer func() {
			if err := recover(); err != nil {
				// Check for a broken connection, as it is not really a
				// condition that warrants a panic stack trace.
				var brokenPipe bool
				if ne, ok := err.(*net.OpError); ok {
					if se, ok := ne.Err.(*os.SyscallError); ok {
						if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
							brokenPipe = true
						}
					}
				}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值