diff --git a/configs/api_config.yaml b/configs/api_config.yaml index 8224f35dc..cff3a10f2 100644 --- a/configs/api_config.yaml +++ b/configs/api_config.yaml @@ -5,11 +5,13 @@ resources: type: restful description: user plugins: - groupNames: - - group2 - pluginNames: - - rate limit - - access + pre: + pluginNames: + - rate limit + - access + post: + groupNames: + - group2 methods: - httpVerb: GET onAir: true diff --git a/go.mod b/go.mod index 19e43cf59..a4dbf6d7f 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/apache/dubbo-go v1.5.5 github.com/apache/dubbo-go-hessian2 v1.7.0 github.com/coreos/etcd v3.3.25+incompatible - github.com/dubbogo/dubbo-go-proxy-filter v0.1.0-rc1.0.20210120132524-c63f4eb13725 //TODO + github.com/dubbogo/dubbo-go-proxy-filter v0.1.0-rc3.0.20210206105825-798f95b07dfa github.com/dubbogo/go-zookeeper v1.0.2 github.com/emirpasic/gods v1.12.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 diff --git a/go.sum b/go.sum index 80625b84c..4aec4b78a 100644 --- a/go.sum +++ b/go.sum @@ -230,8 +230,9 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/dubbogo/dubbo-go-proxy-filter v0.1.0-rc1.0.20210120132524-c63f4eb13725 h1:4KnCNxkDU2PsW6Qi7ZDL11nAGsbZXjbRO7IB3Uy1xx0= -github.com/dubbogo/dubbo-go-proxy-filter v0.1.0-rc1.0.20210120132524-c63f4eb13725/go.mod h1:vy26EhD+06QetexzAI7VAbMor2TtjmbC8f9iRw9lyzA= +github.com/dubbogo/dubbo-go-proxy-filter v0.1.0-rc3 h1:Re7PgmcI/RkjPhIiBbmWJHE/vkmstL89FRbYJGCYnYE= +github.com/dubbogo/dubbo-go-proxy-filter v0.1.0-rc3.0.20210206105825-798f95b07dfa h1:vcZA5dixa3NvX3AFEjhFXykwlRgVbuLgdz96TPnEp2A= +github.com/dubbogo/dubbo-go-proxy-filter v0.1.0-rc3.0.20210206105825-798f95b07dfa/go.mod h1:vy26EhD+06QetexzAI7VAbMor2TtjmbC8f9iRw9lyzA= github.com/dubbogo/go-zookeeper v1.0.2 h1:xmEnPL8SlCe3/+J5ZR9e8qE35LmFVYe8VVpDakjNM4A= github.com/dubbogo/go-zookeeper v1.0.2/go.mod h1:fn6n2CAEer3novYgk9ULLwAjuV8/g4DdC2ENwRb6E+c= github.com/dubbogo/gost v1.9.0/go.mod h1:pPTjVyoJan3aPxBPNUX0ADkXjPibLo+/Ib0/fADXSG8= diff --git a/pkg/config/mock/api_config.yml b/pkg/config/mock/api_config.yml index 0eb0959f3..382a9ef49 100644 --- a/pkg/config/mock/api_config.yml +++ b/pkg/config/mock/api_config.yml @@ -7,11 +7,13 @@ resources: filters: - filter0 plugins: - groupNames: - - group2 - pluginNames: - - rate limit - - access + pre: + pluginNames: + - rate limit + - access + post: + groupNames: + - group2 methods: - httpVerb: GET filters: diff --git a/pkg/filter/plugins/plugins.go b/pkg/filter/plugins/plugins.go index a0d5581a1..467b04932 100644 --- a/pkg/filter/plugins/plugins.go +++ b/pkg/filter/plugins/plugins.go @@ -35,11 +35,17 @@ import ( ) var ( - apiURLWithPluginsMap = make(map[string]context.FilterChain) + apiURLWithPluginsMap = make(map[string]FilterChain) groupWithPluginsMap = make(map[string]map[string]PluginsWithFunc) errEmptyPluginConfig = errors.New("Empty plugin config") ) +//FilterChain include Pre & Post filters +type FilterChain struct { + Pre context.FilterChain + Post context.FilterChain +} + // PluginsWithFunc is a single plugin details type PluginsWithFunc struct { Name string @@ -75,10 +81,10 @@ func InitPluginsGroup(groups []config.PluginsGroup, filePath string) { // InitApiUrlWithFilterChain must behind InitPluginsGroup call func InitAPIURLWithFilterChain(resources []config.Resource) { - pairURLWithFilterChain("", resources, context.FilterChain{}) + pairURLWithFilterChain("", resources, nil) } -func pairURLWithFilterChain(parentPath string, resources []config.Resource, parentFilterFuncs []context.FilterFunc) { +func pairURLWithFilterChain(parentPath string, resources []config.Resource, parentFilterChains *FilterChain) { if len(resources) == 0 { return @@ -95,34 +101,34 @@ func pairURLWithFilterChain(parentPath string, resources []config.Resource, pare continue } - currentFuncArr := getApiFilterFuncsWithPluginsGroup(&resource.Plugins) + currentFilterChains, err := getApiFilterChains(&resource.Plugins) - if len(currentFuncArr) > 0 { - apiURLWithPluginsMap[fullPath] = currentFuncArr - parentFilterFuncs = currentFuncArr + if err == nil { + apiURLWithPluginsMap[fullPath] = *currentFilterChains + parentFilterChains = currentFilterChains } else { - if len(parentFilterFuncs) > 0 { - apiURLWithPluginsMap[fullPath] = parentFilterFuncs + if parentFilterChains != nil { + apiURLWithPluginsMap[fullPath] = *parentFilterChains } } if len(resource.Resources) > 0 { - pairURLWithFilterChain(resource.Path, resource.Resources, parentFilterFuncs) + pairURLWithFilterChain(resource.Path, resource.Resources, parentFilterChains) } } } // GetAPIFilterFuncsWithAPIURL is get filterchain with path -func GetAPIFilterFuncsWithAPIURL(url string) context.FilterChain { +func GetAPIFilterFuncsWithAPIURL(url string) FilterChain { // found from cache - if funcs, found := apiURLWithPluginsMap[url]; found { - logger.Debugf("GetExternalPlugins is:%v,len:%d", funcs, len(funcs)) - return funcs + if flc, found := apiURLWithPluginsMap[url]; found { + logger.Debugf("GetExternalPlugins is:%v", flc) + return flc } // or return empty FilterFunc - return context.FilterChain{} + return FilterChain{context.FilterChain{}, context.FilterChain{}} } func loadExternalPlugin(p *config.Plugin, pl *plugin.Plugin) context.FilterFunc { @@ -141,6 +147,17 @@ func loadExternalPlugin(p *config.Plugin, pl *plugin.Plugin) context.FilterFunc panic(errEmptyPluginConfig) } +func getApiFilterChains(pluginsConfig *config.PluginsConfig) (fcs *FilterChain, err error) { + pre := getApiFilterFuncsWithPluginsGroup(&pluginsConfig.PrePlugins) + post := getApiFilterFuncsWithPluginsGroup(&pluginsConfig.PostPlugins) + + if len(pre) == 0 && len(post) == 0 { + return nil, errors.New("FilterChains is empty") + } + + return &FilterChain{pre, post}, nil +} + func getApiFilterFuncsWithPluginsGroup(plu *config.PluginsInUse) []context.FilterFunc { // not set plugins if nil == plu || nil != plu && len(plu.GroupNames) == 0 && len(plu.PluginNames) == 0 { diff --git a/pkg/filter/plugins/plugins_test.go b/pkg/filter/plugins/plugins_test.go index a8e6a9fb6..016d43787 100644 --- a/pkg/filter/plugins/plugins_test.go +++ b/pkg/filter/plugins/plugins_test.go @@ -28,30 +28,33 @@ import ( "github.com/dubbogo/dubbo-go-proxy/pkg/config" ) -func TestInitPluginsGroup(t *testing.T) { +var ( + mockFile = "../../config/mock/api_config.yml" +) - config, err := config.LoadAPIConfigFromFile("../../../configs/api_config.yaml") +func TestInitPluginsGroup(t *testing.T) { + apiConfig, err := config.LoadAPIConfigFromFile(mockFile) assert.Empty(t, err) - InitPluginsGroup(config.PluginsGroup, config.PluginFilePath) + InitPluginsGroup(apiConfig.PluginsGroup, apiConfig.PluginFilePath) } func TestInitApiUrlWithFilterChain(t *testing.T) { - config, err := config.LoadAPIConfigFromFile("../../../configs/api_config.yaml") + apiConfig, err := config.LoadAPIConfigFromFile(mockFile) assert.Empty(t, err) - InitPluginsGroup(config.PluginsGroup, config.PluginFilePath) - InitAPIURLWithFilterChain(config.Resources) + InitPluginsGroup(apiConfig.PluginsGroup, apiConfig.PluginFilePath) + InitAPIURLWithFilterChain(apiConfig.Resources) } func TestGetApiFilterFuncsWithApiUrl(t *testing.T) { - config, err := config.LoadAPIConfigFromFile("../../../configs/api_config.yaml") + apiConfig, err := config.LoadAPIConfigFromFile(mockFile) assert.Empty(t, err) - InitPluginsGroup(config.PluginsGroup, config.PluginFilePath) - InitAPIURLWithFilterChain(config.Resources) - - fltc := GetAPIFilterFuncsWithAPIURL("/") + InitPluginsGroup(apiConfig.PluginsGroup, apiConfig.PluginFilePath) + InitAPIURLWithFilterChain(apiConfig.Resources) - assert.Equal(t, len(fltc), 0) + flc := GetAPIFilterFuncsWithAPIURL("/") + assert.Equal(t, 0, len(flc.Pre)) + assert.Equal(t, 0, len(flc.Post)) } diff --git a/pkg/proxy/listener.go b/pkg/proxy/listener.go index 69c6f3e77..9318c4346 100644 --- a/pkg/proxy/listener.go +++ b/pkg/proxy/listener.go @@ -163,15 +163,14 @@ func addFilter(ctx *h.HttpContext, api router.API) { case fc.HTTPRequest: httpFilter(ctx, api.Method.IntegrationRequest) } + // load plugins + pluginsFilter := plugins.GetAPIFilterFuncsWithAPIURL(ctx.Request.URL.Path) + ctx.AppendFilterFunc(pluginsFilter.Pre...) ctx.AppendFilterFunc(header.New().Do(), extension.GetMustFilterFunc(constant.RemoteCallFilter)) - ctx.BuildFilters() - // load plugins - filterChain := plugins.GetAPIFilterFuncsWithAPIURL(ctx.Request.URL.Path) - ctx.AppendFilterFunc(filterChain...) - + ctx.AppendFilterFunc(pluginsFilter.Post...) ctx.AppendFilterFunc(extension.GetMustFilterFunc(constant.ResponseFilter)) } diff --git a/samples/plugins/README_CN.md b/samples/plugins/README_CN.md index 55b666a5e..92b122ee0 100644 --- a/samples/plugins/README_CN.md +++ b/samples/plugins/README_CN.md @@ -16,7 +16,9 @@ > 插件实现和主应用程序都必须使用**完全相同**的公共依赖项,在本例中唯一的公共依赖项是[github.com/dubbogo/dubbo-go-proxy-filter](https://github.com/dubbogo/dubbo-go-proxy-filter)。所以,请务必保证其与Proxy中的版本一致。 - +- 不支持Windows + + > 建议使用Docker或虚拟机 diff --git a/samples/plugins/config/api_config.yaml b/samples/plugins/config/api_config.yaml index 057ccb2f8..a9bbd7ec1 100644 --- a/samples/plugins/config/api_config.yaml +++ b/samples/plugins/config/api_config.yaml @@ -5,11 +5,13 @@ resources: type: restful description: user plugins: - groupNames: - - group2 - pluginNames: - - rate limit - - access + pre: + pluginNames: + - rate limit + - access + post: + groupNames: + - group2 methods: - httpVerb: POST onAir: true diff --git a/samples/plugins/go.mod b/samples/plugins/go.mod index 0f4837c51..516e49f82 100644 --- a/samples/plugins/go.mod +++ b/samples/plugins/go.mod @@ -2,4 +2,7 @@ module dubbo-go-proxy/samples/plugins go 1.14 -require github.com/dubbogo/dubbo-go-proxy-filter v0.1.0-rc1.0.20210120132524-c63f4eb13725 //TODO + +require ( + github.com/dubbogo/dubbo-go-proxy-filter v0.1.0-rc3.0.20210206105825-798f95b07dfa +)