当前位置: 首页 > article >正文

[每周一更]-(第127期):Go新项目-Gin中使用超时中间件实战(11)

在这里插入图片描述

在项目不断迭代过程中,发现基础架构中,没有进行超时控制,有些接口由于网络延迟以及远程调用等情况存在请求时间过长的问题,消耗了资源,也降低了用户体验,这一讲我们聊下超时控制中间件,来完善我们的基础架构,这里我们采用Context来实现。

在 Gin 框架中,如果某些接口需要明确的超时时间(例如避免长时间阻塞的请求),可以使用一个针对接口超时时间的中间件。这种中间件可以为每个请求设置一个上下文(context.Context),并通过 context.WithTimeout 来管理请求的生命周期。

是否需要超时中间件?

  1. 建议场景
    • 接口耗时不确定:接口依赖外部服务(如第三方 API、数据库),且响应时间可能超出预期。
    • 系统资源保护:防止某些慢请求长时间占用资源,影响整体服务质量。
    • 全局或局部控制:希望为不同接口配置灵活的超时时间。
  2. 不建议场景
    • 接口响应时间确定:接口处理非常快,且耗时由客户端控制。
    • 已经在业务代码中实现:如果在具体服务逻辑中已经实现了超时控制,则无需重复配置。
1. 基于 context.WithTimeout

可以使用 context.WithTimeout 在中间件中设置超时时间,并在业务逻辑中检查上下文是否被取消。

示例代码:

package main

import (
	"context"
	"fmt"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
)

func TimeoutMiddleware(timeout time.Duration) gin.HandlerFunc {
	return func(c *gin.Context) {
		// 设置超时上下文
		ctx, cancel := context.WithTimeout(c.Request.Context(), timeout)
		defer cancel()

		// 将上下文传递给请求
		c.Request = c.Request.WithContext(ctx)

		// 创建一个 channel 来监控请求是否完成
		done := make(chan struct{})
		go func() {
			c.Next() // 执行后续处理
			close(done) //关闭通道
		}()

		// 监听完成或超时
		select {
		case <-ctx.Done():
			c.JSON(http.StatusGatewayTimeout, gin.H{"error": "request timeout"})
			c.Abort()
		case <-done:
			// 请求正常完成
		}
	}
}

func main() {
	r := gin.Default()

	// 应用超时中间件
	r.Use(TimeoutMiddleware(2 * time.Second))

	// 示例接口
	r.GET("/slow", func(c *gin.Context) {
		time.Sleep(3 * time.Second) // 模拟慢请求
		c.JSON(http.StatusOK, gin.H{"message": "success"})
	})

	r.GET("/fast", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"message": "fast response"})
	})

	r.Run(":8080")
}

代码部分解释:

通道的初始化与关闭

  • done 是一个无缓冲通道,用于在任务完成后发送信号。

  • close(done) 会关闭通道,所有监听 <-done 的协程会收到一个零值信号,表示通道已关闭。

select 监听通道

  • done 被关闭时,case <-done 会触发。

  • ctx.Done() 是一个Context超时接收信号,超时后触发对应 case

并发安全性

  • 由于 close(done) 只会触发一次,select 的分支会优雅处理不同情况,避免竞争。
2. 为特定接口设置不同超时时间

可以在路由组中绑定超时中间件,实现针对性控制:

// 路由组 A,超时时间 1 秒
groupA := r.Group("/groupA")
groupA.Use(TimeoutMiddleware(1 * time.Second))
groupA.GET("/example", exampleHandler)

// 路由组 B,超时时间 5 秒
groupB := r.Group("/groupB")
groupB.Use(TimeoutMiddleware(5 * time.Second))
groupB.GET("/example", exampleHandler)

注意事项

  1. 超时后的清理: 如果使用 Goroutine 执行任务,请确保超时后停止任务或避免资源泄露。

  2. 客户端超时 vs 服务端超时: 服务端超时主要保护后端资源,但客户端也需要设置合理的超时,避免占用连接资源。

  3. 灵活性: 对于不同接口,超时时间可通过配置文件或环境变量管理。

操作channel的3种方式

操作nil的channel正常channel已关闭的channel
读 <-ch阻塞成功或阻塞读到零值
写 ch<-阻塞成功或阻塞panic
关闭 close(ch)panic成功panic

Gin 中增加超时中间件是控制请求生命周期、优化资源管理的有效方式,特别适用于需要保护资源和灵活处理超时的场景。通过 context.WithTimeout 配合中间件,可以轻松实现针对接口的超时管理逻辑。


http://www.kler.cn/a/442233.html

相关文章:

  • Red Hat8:搭建FTP服务器
  • ubuntu22.04安装注意点
  • C#表达式和运算符
  • 深入理解 Entity、VO、QO、DTO 的区别及其在 MVC 架构中的应用
  • 将图像输入批次扁平化为CNN
  • SUN的J2EE与微软的DNA
  • 【深度学习基础】Windows实时查看GPU显存占用、功耗、进程状态
  • USB-A/C 2in1接口的未来应用前景分析
  • JAVA入门:使用IDE开发
  • 多模态检索增强生成
  • HarmonyOS 实时监听与获取 Wi-Fi 信息
  • 解锁Vue组件的奇妙世界
  • 【YashanDB知识库】数据库一主一备部署及一主两备部署时,主备手动切换方法及自动切换配置
  • 算法,递归和迭代
  • 交换机堆叠和集群
  • 线性池学习
  • vue登录成功之后的token处理
  • 【JS/TS鼠标气泡跟随】文本提示 / 操作提示
  • access数据库代做/mysql代做/Sql server数据库代做辅导设计服务
  • Jackson @JsonRootName 注解
  • Python | 虚拟环境04 - Qt Creator设置Python虚拟环境
  • HarmonyOS Next开发工具DevEco Studio介绍:ASan与TSan检测根治你的C++恐惧症
  • 使用k6进行kafka负载测试
  • 允许某段网络访问Linux服务器上的MariaDB
  • Excel技巧:使用PowerQuery批量提取文件名
  • 如何在铁威马NAS上安装内网穿透,实现对铁威马NAS的远程访问管理