From 69cd3f946096e6210c5f513dc81bc3f61353f68b Mon Sep 17 00:00:00 2001 From: aerox Date: Mon, 9 Mar 2020 12:32:32 +0800 Subject: [PATCH 1/5] fix 49; init commit --- adapter/gin/middleware.go | 39 +++++++++ adapter/gin/middleware_example_test.go | 29 +++++++ adapter/gin/middleware_test.go | 108 +++++++++++++++++++++++++ adapter/gin/option.go | 36 +++++++++ go.mod | 2 + go.sum | 26 ++++++ 6 files changed, 240 insertions(+) create mode 100644 adapter/gin/middleware.go create mode 100644 adapter/gin/middleware_example_test.go create mode 100644 adapter/gin/middleware_test.go create mode 100644 adapter/gin/option.go diff --git a/adapter/gin/middleware.go b/adapter/gin/middleware.go new file mode 100644 index 000000000..f4acd753f --- /dev/null +++ b/adapter/gin/middleware.go @@ -0,0 +1,39 @@ +package gin + +import ( + "net/http" + + sentinel "github.com/alibaba/sentinel-golang/api" + "github.com/alibaba/sentinel-golang/core/base" + "github.com/gin-gonic/gin" +) + +// SentinelMiddleware +func SentinelMiddleware(opts ...Option) gin.HandlerFunc { + options := evaluateOptions(opts) + return func(c *gin.Context) { + resourceName := c.Request.Method + "_" + c.Request.URL.Path + + if options.resourceExtract != nil { + resourceName = options.resourceExtract(c) + } + + entry, err := sentinel.Entry( + resourceName, + sentinel.WithResourceType(base.ResTypeWeb), + sentinel.WithTrafficType(base.Inbound), + ) + + if err != nil { + if options.blockFallback != nil { + options.blockFallback(c) + } else { + c.AbortWithStatus(http.StatusTooManyRequests) + } + return + } + + defer entry.Exit() + c.Next() + } +} \ No newline at end of file diff --git a/adapter/gin/middleware_example_test.go b/adapter/gin/middleware_example_test.go new file mode 100644 index 000000000..46276873d --- /dev/null +++ b/adapter/gin/middleware_example_test.go @@ -0,0 +1,29 @@ +package gin + +import ( + "github.com/gin-gonic/gin" +) + +func Example() { + r := gin.New() + r.Use( + SentinelMiddleware( + // customize resource extractor if required + // method_path by default + WithResourceExtract(func(ctx *gin.Context) string { + return ctx.GetHeader("X-Real-IP") + }), + // customize block fallback if required + // abort with status 429 by default + WithBlockFallback(func(ctx *gin.Context){ + ctx.AbortWithStatusJSON(400, map[string]interface{}{ + "err": "too many request; the quota used up", + "code": 10222, + }) + }), + ), + ) + + r.GET("/test", func(c *gin.Context) { }) + _ = r.Run(":0") +} diff --git a/adapter/gin/middleware_test.go b/adapter/gin/middleware_test.go new file mode 100644 index 000000000..d94cd7658 --- /dev/null +++ b/adapter/gin/middleware_test.go @@ -0,0 +1,108 @@ +package gin + +import ( + "io" + "net/http" + "net/http/httptest" + "testing" + + sentinel "github.com/alibaba/sentinel-golang/api" + "github.com/alibaba/sentinel-golang/core/flow" + "github.com/bmizerany/assert" + "github.com/gin-gonic/gin" +) + +func initSentinel(t *testing.T) { + err := sentinel.InitDefault() + if err != nil { + t.Fatalf("Unexpected error: %+v", err) + } + + _, err = flow.LoadRules([]*flow.FlowRule{ + { + Resource: "GET_/ping", + MetricType: flow.QPS, + Count: 1, + ControlBehavior: flow.Reject, + }, + { + Resource: "/ping", + MetricType: flow.QPS, + Count: 0, + ControlBehavior: flow.Reject, + }, + }) + if err != nil { + t.Fatalf("Unexpected error: %+v", err) + return + } +} + +func TestSentinelMiddleware(t *testing.T) { + type args struct { + opts []Option + method string + path string + handler func(ctx *gin.Context) + body io.Reader + } + type want struct { + code int + } + var ( + tests = []struct { + name string + args args + want want + }{ + { + name: "default get", + args: args{ + opts: []Option{}, + method: http.MethodGet, + path: "/ping", + handler: func(ctx *gin.Context) { + ctx.String(http.StatusOK, "ping") + }, + body: nil, + }, + want: want{ + code:http.StatusOK, + }, + }, + { + name: "customize resource extract", + args: args{ + opts: []Option{ + WithResourceExtract(func(ctx *gin.Context) string { + return ctx.Request.URL.Path + }), + }, + method: http.MethodGet, + path: "/ping", + handler: func(ctx *gin.Context) { + ctx.String(http.StatusOK, "ping") + }, + body: nil, + }, + want: want{ + code:http.StatusTooManyRequests, + }, + }, + } + ) + initSentinel(t) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + router := gin.New() + router.Use(SentinelMiddleware(tt.args.opts...)) + router.Handle(tt.args.method, tt.args.path, tt.args.handler) + r := httptest.NewRequest(tt.args.method, tt.args.path, nil) + w := httptest.NewRecorder() + router.ServeHTTP(w, r) + + assert.Equal(t, tt.want.code, w.Code) + }) + } +} \ No newline at end of file diff --git a/adapter/gin/option.go b/adapter/gin/option.go new file mode 100644 index 000000000..730db19a8 --- /dev/null +++ b/adapter/gin/option.go @@ -0,0 +1,36 @@ +package gin + +import ( + "github.com/gin-gonic/gin" +) + +type ( + Option func(*options) + options struct { + resourceExtract func(*gin.Context) string + blockFallback func(*gin.Context) + } +) + +func evaluateOptions(opts []Option) *options { + optCopy := &options{} + for _, opt := range opts { + opt(optCopy) + } + + return optCopy +} + +// WithResourceExtract set resourceExtract +func WithResourceExtract(fn func(*gin.Context) string) Option { + return func(opts *options) { + opts.resourceExtract = fn + } +} + +// WithBlockFallback set blockFallback +func WithBlockFallback(fn func(ctx *gin.Context)) Option { + return func(opts *options) { + opts.blockFallback = fn + } +} \ No newline at end of file diff --git a/go.mod b/go.mod index 1a0f55906..f52fe635e 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,8 @@ go 1.13 require ( github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/apache/dubbo-go v0.1.2-0.20200224151332-dd1a3c24d656 + github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 + github.com/gin-gonic/gin v1.5.0 github.com/go-ole/go-ole v1.2.4 // indirect github.com/pkg/errors v0.8.1 github.com/shirou/gopsutil v2.19.12+incompatible diff --git a/go.sum b/go.sum index 5e8a8e196..62165713f 100644 --- a/go.sum +++ b/go.sum @@ -36,6 +36,7 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= @@ -77,6 +78,10 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/structs v0.0.0-20180123065059-ebf56d35bba7/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc= +github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -86,6 +91,10 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= +github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= +github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= +github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= +github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-sql-driver/mysql v0.0.0-20180618115901-749ddf1598b4/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= @@ -100,6 +109,7 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -179,6 +189,7 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22 github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -193,6 +204,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= +github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570/go.mod h1:BLt8L9ld7wVsvEWQbuLrUZnCMnUmLZ+CGDzKtclrTlE= github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f/go.mod h1:UGmTpUd3rjbtfIpwAPrcfmGf/Z1HS95TATB+m57TPB8= github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042/go.mod h1:TPpsiPUEh0zFL1Snz4crhMlBe60PYxRHr5oFF3rRYg0= @@ -201,6 +214,8 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -215,8 +230,10 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nacos-group/nacos-sdk-go v0.0.0-20190723125407-0242d42e3dbb/go.mod h1:CEkSvEpoveoYjA81m4HNeYQ0sge0LFGKSEqO3JKHllo= @@ -290,6 +307,10 @@ github.com/tevid/gohamcrest v1.1.1/go.mod h1:3UvtWlqm8j5JbwYZh80D/PVBt0mJ1eJiYgZ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3/go.mod h1:QDlpd3qS71vYtakd2hmdpqhJ9nwv6mD6A30bQ1BPBFE= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/zouyx/agollo v0.0.0-20191114083447-dde9fc9f35b8/go.mod h1:S1cAa98KMFv4Sa8SbJ6ZtvOmf0VlgH0QJ1gXI0lBfBY= @@ -335,6 +356,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190508220229-2d0786266e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200107162124-548cf772de50 h1:YvQ10rzcqWXLlJZ3XCUoO25savxmscf4+SC+ZqiCHhA= golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -363,6 +385,10 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= +gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20160818020120-3f83fa500528/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= From 4b7b55afafaeb46c98f3013e15045af1198d4622 Mon Sep 17 00:00:00 2001 From: aerox Date: Mon, 9 Mar 2020 12:35:44 +0800 Subject: [PATCH 2/5] fix #49; add unit tests for gin --- adapter/gin/middleware_test.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/adapter/gin/middleware_test.go b/adapter/gin/middleware_test.go index d94cd7658..912691fec 100644 --- a/adapter/gin/middleware_test.go +++ b/adapter/gin/middleware_test.go @@ -89,6 +89,28 @@ func TestSentinelMiddleware(t *testing.T) { code:http.StatusTooManyRequests, }, }, + { + name: "customize block fallback", + args: args{ + opts: []Option{ + WithResourceExtract(func(ctx *gin.Context) string { + return ctx.Request.URL.Path + }), + WithBlockFallback(func(ctx *gin.Context) { + ctx.String(http.StatusBadRequest, "block") + }), + }, + method: http.MethodGet, + path: "/ping", + handler: func(ctx *gin.Context) { + ctx.String(http.StatusOK, "ping") + }, + body: nil, + }, + want: want{ + code:http.StatusBadRequest, + }, + }, } ) initSentinel(t) From aa257f8fcfe1b97792aeb16bee8cd88c8fdb5ff0 Mon Sep 17 00:00:00 2001 From: aerox Date: Mon, 9 Mar 2020 23:43:44 +0800 Subject: [PATCH 3/5] fix #52; update option --- adapter/gin/middleware.go | 2 +- adapter/gin/middleware_example_test.go | 2 +- adapter/gin/middleware_test.go | 4 ++-- adapter/gin/option.go | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/adapter/gin/middleware.go b/adapter/gin/middleware.go index f4acd753f..1d99bb031 100644 --- a/adapter/gin/middleware.go +++ b/adapter/gin/middleware.go @@ -12,7 +12,7 @@ import ( func SentinelMiddleware(opts ...Option) gin.HandlerFunc { options := evaluateOptions(opts) return func(c *gin.Context) { - resourceName := c.Request.Method + "_" + c.Request.URL.Path + resourceName := c.Request.Method + ":" + c.Request.URL.Path if options.resourceExtract != nil { resourceName = options.resourceExtract(c) diff --git a/adapter/gin/middleware_example_test.go b/adapter/gin/middleware_example_test.go index 46276873d..18ba50ffc 100644 --- a/adapter/gin/middleware_example_test.go +++ b/adapter/gin/middleware_example_test.go @@ -10,7 +10,7 @@ func Example() { SentinelMiddleware( // customize resource extractor if required // method_path by default - WithResourceExtract(func(ctx *gin.Context) string { + WithResourceExtractor(func(ctx *gin.Context) string { return ctx.GetHeader("X-Real-IP") }), // customize block fallback if required diff --git a/adapter/gin/middleware_test.go b/adapter/gin/middleware_test.go index 912691fec..86184e086 100644 --- a/adapter/gin/middleware_test.go +++ b/adapter/gin/middleware_test.go @@ -74,7 +74,7 @@ func TestSentinelMiddleware(t *testing.T) { name: "customize resource extract", args: args{ opts: []Option{ - WithResourceExtract(func(ctx *gin.Context) string { + WithResourceExtractor(func(ctx *gin.Context) string { return ctx.Request.URL.Path }), }, @@ -93,7 +93,7 @@ func TestSentinelMiddleware(t *testing.T) { name: "customize block fallback", args: args{ opts: []Option{ - WithResourceExtract(func(ctx *gin.Context) string { + WithResourceExtractor(func(ctx *gin.Context) string { return ctx.Request.URL.Path }), WithBlockFallback(func(ctx *gin.Context) { diff --git a/adapter/gin/option.go b/adapter/gin/option.go index 730db19a8..66c98d7fe 100644 --- a/adapter/gin/option.go +++ b/adapter/gin/option.go @@ -21,8 +21,8 @@ func evaluateOptions(opts []Option) *options { return optCopy } -// WithResourceExtract set resourceExtract -func WithResourceExtract(fn func(*gin.Context) string) Option { +// WithResourceExtractor set resourceExtract +func WithResourceExtractor(fn func(*gin.Context) string) Option { return func(opts *options) { opts.resourceExtract = fn } From d8149bab6791ef9542822ce067be2e8d712174b8 Mon Sep 17 00:00:00 2001 From: aerox Date: Tue, 10 Mar 2020 22:27:06 +0800 Subject: [PATCH 4/5] rm github.com/bmizerany/assert --- adapter/gin/middleware_test.go | 2 +- go.mod | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/adapter/gin/middleware_test.go b/adapter/gin/middleware_test.go index 86184e086..6176476d8 100644 --- a/adapter/gin/middleware_test.go +++ b/adapter/gin/middleware_test.go @@ -8,8 +8,8 @@ import ( sentinel "github.com/alibaba/sentinel-golang/api" "github.com/alibaba/sentinel-golang/core/flow" - "github.com/bmizerany/assert" "github.com/gin-gonic/gin" + "github.com/stretchr/testify/assert" ) func initSentinel(t *testing.T) { diff --git a/go.mod b/go.mod index f52fe635e..c850a1cc6 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.13 require ( github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/apache/dubbo-go v0.1.2-0.20200224151332-dd1a3c24d656 - github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 github.com/gin-gonic/gin v1.5.0 github.com/go-ole/go-ole v1.2.4 // indirect github.com/pkg/errors v0.8.1 From b2b60c52f1aee20deda1e9a35f6cb3a8c4eb6823 Mon Sep 17 00:00:00 2001 From: aerox Date: Sat, 14 Mar 2020 21:23:25 +0800 Subject: [PATCH 5/5] fix #49; modify resource name separator --- adapter/gin/middleware.go | 7 +++++-- adapter/gin/middleware_test.go | 19 ++++++++++--------- adapter/gin/option.go | 2 +- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/adapter/gin/middleware.go b/adapter/gin/middleware.go index 1d99bb031..1d44d9f74 100644 --- a/adapter/gin/middleware.go +++ b/adapter/gin/middleware.go @@ -8,11 +8,14 @@ import ( "github.com/gin-gonic/gin" ) -// SentinelMiddleware +// SentinelMiddleware returns new gin.HandlerFunc +// Default resource name is {method}:{path}, such as "GET:/api/users/:id" +// Default block fallback is returning 429 code +// Define your own behavior by setting options func SentinelMiddleware(opts ...Option) gin.HandlerFunc { options := evaluateOptions(opts) return func(c *gin.Context) { - resourceName := c.Request.Method + ":" + c.Request.URL.Path + resourceName := c.Request.Method + ":" + c.FullPath() if options.resourceExtract != nil { resourceName = options.resourceExtract(c) diff --git a/adapter/gin/middleware_test.go b/adapter/gin/middleware_test.go index 6176476d8..4837b716c 100644 --- a/adapter/gin/middleware_test.go +++ b/adapter/gin/middleware_test.go @@ -20,13 +20,13 @@ func initSentinel(t *testing.T) { _, err = flow.LoadRules([]*flow.FlowRule{ { - Resource: "GET_/ping", + Resource: "GET:/ping", MetricType: flow.QPS, Count: 1, ControlBehavior: flow.Reject, }, { - Resource: "/ping", + Resource: "/api/users/:id", MetricType: flow.QPS, Count: 0, ControlBehavior: flow.Reject, @@ -43,6 +43,7 @@ func TestSentinelMiddleware(t *testing.T) { opts []Option method string path string + reqPath string handler func(ctx *gin.Context) body io.Reader } @@ -61,6 +62,7 @@ func TestSentinelMiddleware(t *testing.T) { opts: []Option{}, method: http.MethodGet, path: "/ping", + reqPath: "/ping", handler: func(ctx *gin.Context) { ctx.String(http.StatusOK, "ping") }, @@ -75,11 +77,12 @@ func TestSentinelMiddleware(t *testing.T) { args: args{ opts: []Option{ WithResourceExtractor(func(ctx *gin.Context) string { - return ctx.Request.URL.Path + return ctx.FullPath() }), }, - method: http.MethodGet, - path: "/ping", + method: http.MethodPost, + path: "/api/users/:id", + reqPath: "/api/users/123", handler: func(ctx *gin.Context) { ctx.String(http.StatusOK, "ping") }, @@ -93,15 +96,13 @@ func TestSentinelMiddleware(t *testing.T) { name: "customize block fallback", args: args{ opts: []Option{ - WithResourceExtractor(func(ctx *gin.Context) string { - return ctx.Request.URL.Path - }), WithBlockFallback(func(ctx *gin.Context) { ctx.String(http.StatusBadRequest, "block") }), }, method: http.MethodGet, path: "/ping", + reqPath: "/ping", handler: func(ctx *gin.Context) { ctx.String(http.StatusOK, "ping") }, @@ -120,7 +121,7 @@ func TestSentinelMiddleware(t *testing.T) { router := gin.New() router.Use(SentinelMiddleware(tt.args.opts...)) router.Handle(tt.args.method, tt.args.path, tt.args.handler) - r := httptest.NewRequest(tt.args.method, tt.args.path, nil) + r := httptest.NewRequest(tt.args.method, tt.args.reqPath, nil) w := httptest.NewRecorder() router.ServeHTTP(w, r) diff --git a/adapter/gin/option.go b/adapter/gin/option.go index 66c98d7fe..548087d20 100644 --- a/adapter/gin/option.go +++ b/adapter/gin/option.go @@ -21,7 +21,7 @@ func evaluateOptions(opts []Option) *options { return optCopy } -// WithResourceExtractor set resourceExtract +// WithResourceExtractor set resourceExtractor func WithResourceExtractor(fn func(*gin.Context) string) Option { return func(opts *options) { opts.resourceExtract = fn