原理
每次访问redis会记住IP地址为key,值为0。每次访问值就会加一,达到设定好的访问限制后就会返回403。直到60秒后redis缓存失效。
准备
- redis 安装就不再说明了,某度一下很简单。笔者使用的是某塔自带的redis,傻瓜安装。
- 安装Go的redis依赖。
文件树
├─main.go
└─middlewares
└─middlewares.go
main.go
package main
import (
"net/http"
"./middlewares"
"github.com/gin-gonic/gin"
"github.com/thinkerou/favicon"
)
func main() {
// 启动redis
err := middlewares.InitClient()
if err != nil {
//redis连接错误
panic(err)
}
fmt.Println("Redis连接成功")
router := gin.Default()
// 网站图标
router.Use(favicon.New("./ay.ico"))
// 防火墙中间件
router.Use(middlewares.RateMiddleware)
// 没有页面返回
router.NoRoute(func(context *gin.Context) {
context.IndentedJSON(http.StatusNotFound, gin.H{
"code": 404,
"data": "Page Not Found",
"msg": "https://api.y-alpha.com/",
})
})
// 重定向
router.GET("/", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "https://baidu.com/")
})
// 8080端口监听
router.Run(":8080")
}
middlewares.go
package middlewares
import (
"context"
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/go-redis/redis"
)
var redisDb *redis.Client
// 连接到redis
func InitClient() (err error) {
redisDb = redis.NewClient(&redis.Options{
Addr: "localhost:6379", // redis地址
Password: "", // redis密码,没有则留空
DB: 0, // 默认数据库,默认是0
})
//通过 *redis.Client.Ping() 来检查是否成功连接到了redis服务器
_, err = redisDb.Ping(context.TODO()).Result()
if err != nil {
return err
}
return nil
}
// 防火墙中间件
func RateMiddleware(c *gin.Context) {
// 60 秒刷新key为IP(c.ClientIP())的r值为0
err := redisDb.SetNX(context.TODO(), c.ClientIP(), 0, 60*time.Second).Err()
// 每次访问,这个IP的对应的值加一
redisDb.Incr(context.TODO(), c.ClientIP())
if err != nil {
panic(err)
}
// 获取IP访问的次数
var val int
val, err = redisDb.Get(context.TODO(), c.ClientIP()).Int()
if err != nil {
panic(err)
}
// 如果大于60次,返回403
if val > 60 {
c.Abort()
c.JSON(http.StatusForbidden, gin.H{
"code": 403,
"data": "IP Ban, please try again later",
})
return
} else {
// 到下一个中间件
c.Next()
}
}