timeout limitrate middleware but look like invalid

This commit is contained in:
xing 2021-06-01 17:40:51 +08:00
parent fe2f6850f9
commit 5dab1f64cd
6 changed files with 127 additions and 4 deletions

1
go.mod
View File

@ -18,6 +18,7 @@ require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/jinzhu/gorm v1.9.16
github.com/json-iterator/go v1.1.11 // indirect
github.com/juju/ratelimit v1.0.1 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/mailru/easyjson v0.7.7 // indirect

View File

@ -0,0 +1,17 @@
package middleware
import (
"context"
"github.com/gin-gonic/gin"
"time"
)
func ContextTimeout(t time.Duration) func(c *gin.Context) {
return func(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), t)
defer cancel()
c.Request = c.Request.WithContext(ctx)
c.Next()
}
}

View File

@ -0,0 +1,25 @@
package middleware
import (
"blog/pkg/app"
"blog/pkg/errorcode"
"blog/pkg/limiter"
"github.com/gin-gonic/gin"
)
func RateLimiter(l limiter.LimiterIface) gin.HandlerFunc {
return func(c *gin.Context) {
key := l.Key(c)
if bucket, ok := l.GetBucket(key); ok {
count := bucket.TakeAvailable(1)
if count == 0 {
response := app.NewResponse(c)
response.ToErrorResponse(errorcode.TooManyRequests)
c.Abort()
return
}
}
c.Next()
}
}

View File

@ -6,19 +6,33 @@ import (
"blog/internal/middleware"
"blog/internal/routess/api"
v1 "blog/internal/routess/api/v1"
"blog/pkg/limiter"
"github.com/gin-gonic/gin"
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
"net/http"
"time"
)
var methodLimiters = limiter.NewMethodLimiter().AddBuckets(limiter.LimiterBucketRule{
Key: "/auth",
FillInterval: time.Second,
Capacity: 10,
Quantum: 10,
})
func NewRouter() *gin.Engine {
r := gin.New()
r.Use(gin.Logger())
r.Use(gin.Recovery())
if global.ServerSetting.RunMode == "debug" {
r.Use(gin.Logger())
r.Use(gin.Recovery())
} else {
r.Use(middleware.AccessLog())
r.Use(middleware.Recovery())
}
r.Use(middleware.Translations())
r.Use(middleware.Recovery())
r.Use(middleware.AccessLog())
r.Use(middleware.RateLimiter(methodLimiters))
r.Use(middleware.ContextTimeout(60 * time.Second))
article := v1.NewArticle()
tag := v1.NewTag()
upload := api.NewUpload()

24
pkg/limiter/limiter.go Normal file
View File

@ -0,0 +1,24 @@
package limiter
import (
"github.com/gin-gonic/gin"
"github.com/juju/ratelimit"
"time"
)
type LimiterIface interface {
Key(c *gin.Context) string
GetBucket(key string) (*ratelimit.Bucket, bool)
AddBuckets(rules ...LimiterBucketRule) LimiterIface
}
type Limiter struct {
limiterBuckets map[string]*ratelimit.Bucket
}
type LimiterBucketRule struct {
Key string
FillInterval time.Duration
Capacity int64
Quantum int64
}

View File

@ -0,0 +1,42 @@
package limiter
import (
"github.com/gin-gonic/gin"
"github.com/juju/ratelimit"
"strings"
)
type MethodLimiter struct {
*Limiter
}
func NewMethodLimiter() LimiterIface {
return MethodLimiter{
Limiter: &Limiter{limiterBuckets: make(map[string]*ratelimit.Bucket)},
}
}
func (l MethodLimiter) Key(c *gin.Context) string {
uri := c.Request.RequestURI
index := strings.Index(uri, "?")
if index == -1 {
return uri
}
return uri[:index]
}
func (l MethodLimiter) GetBucket(key string) (*ratelimit.Bucket, bool) {
bucket, ok := l.limiterBuckets[key]
return bucket, ok
}
func (l MethodLimiter) AddBuckets(rules ...LimiterBucketRule) LimiterIface {
for _, rule := range rules {
if _, ok := l.limiterBuckets[rule.Key]; !ok {
l.limiterBuckets[rule.Key] = ratelimit.NewBucketWithQuantum(rule.FillInterval, rule.Capacity, rule.Quantum)
}
}
return l
}