gin结合go-redis根据ip完成访问频率限制

4 篇文章 0 订阅
import (
	"time"

	"github.com/go-redis/redis"
)

// Limiter 定义属性
type Limiter struct {
	// Redis client connection.
	rc *redis.Client
}

// 根据redisURL创建新的limiter并返回
func NewLimiter(redisURL string) (*Limiter, error) {
	opts, err := redis.ParseURL(redisURL)
	if err != nil {
		return nil, err
	}

	rc := redis.NewClient(opts)
	if err := rc.Ping().Err(); err != nil {
		return nil, err
	}

	return &Limiter{rc: rc}, nil
}

// 通过redis的value判断第几次访问并返回是否允许访问
func (l *Limiter) Allow(key string, events int64, per time.Duration) bool {
	curr := l.rc.LLen(key).Val()
	if curr >= events {
		return false
	}

	if v := l.rc.Exists(key).Val(); v == 0 {
		pipe := l.rc.TxPipeline()
		pipe.RPush(key, key)
		//设置过期时间
		pipe.Expire(key, per)
		_, _ = pipe.Exec()
	} else {
		l.rc.RPushX(key, key)
	}

	return true
}

main.go

func main(){
	router := gin.Default()
	//创建一个新limiter.
	limiter, err := util.NewLimiter("redis://localhost:6379")
	if err != nil {
		log.Fatal(err)
	}
	router.Use(middlewares.RateMiddleware(limiter))
	router.run()
}

meddlewares.go

//限制访问
func RateMiddleware(limiter *util.Limiter) gin.HandlerFunc {
	return func(c *gin.Context) {
		// 如果ip请求连接数在两秒内超过5次,返回429并抛出error
		if !limiter.Allow(c.ClientIP(), 5, 2*time.Second) {
			c.AbortWithStatusJSON(http.StatusTooManyRequests, gin.H{
				"error": "too many requests",
			})
			log.Println("too many requests")
			return
		}
		c.Next()
	}
}
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值