@@ -42,18 +42,27 @@ import com.alibaba.csp.sentinel.util.StringUtil; | |||||
/*** | /*** | ||||
* Servlet filter that integrates with Sentinel. | * Servlet filter that integrates with Sentinel. | ||||
* | * | ||||
* @author zhaoyuguang | |||||
* @author youji.zj | * @author youji.zj | ||||
* @author Eric Zhao | * @author Eric Zhao | ||||
*/ | */ | ||||
public class CommonFilter implements Filter { | public class CommonFilter implements Filter { | ||||
private final static String HTTP_METHOD_SPECIFY = "HTTP_METHOD_SPECIFY"; | private final static String HTTP_METHOD_SPECIFY = "HTTP_METHOD_SPECIFY"; | ||||
/** | |||||
* Use the path of the url as the context, if necessary, but pay attention to the number of context EntranceNode | |||||
*/ | |||||
public final static String WEB_CONTEXT_UNIFY = "WEB_CONTEXT_UNIFY"; | |||||
private final static String COLON = ":"; | private final static String COLON = ":"; | ||||
private boolean httpMethodSpecify = false; | private boolean httpMethodSpecify = false; | ||||
private boolean webContextUnify = true; | |||||
@Override | @Override | ||||
public void init(FilterConfig filterConfig) { | public void init(FilterConfig filterConfig) { | ||||
httpMethodSpecify = Boolean.parseBoolean(filterConfig.getInitParameter(HTTP_METHOD_SPECIFY)); | httpMethodSpecify = Boolean.parseBoolean(filterConfig.getInitParameter(HTTP_METHOD_SPECIFY)); | ||||
if (filterConfig.getInitParameter(WEB_CONTEXT_UNIFY) != null) { | |||||
webContextUnify = Boolean.parseBoolean(filterConfig.getInitParameter(WEB_CONTEXT_UNIFY)); | |||||
} | |||||
} | } | ||||
@Override | @Override | ||||
@@ -78,7 +87,7 @@ public class CommonFilter implements Filter { | |||||
if (!StringUtil.isEmpty(target)) { | if (!StringUtil.isEmpty(target)) { | ||||
// Parse the request origin using registered origin parser. | // Parse the request origin using registered origin parser. | ||||
String origin = parseOrigin(sRequest); | String origin = parseOrigin(sRequest); | ||||
ContextUtil.enter(WebServletConfig.WEB_SERVLET_CONTEXT_NAME, origin); | |||||
ContextUtil.enter(webContextUnify ? WebServletConfig.WEB_SERVLET_CONTEXT_NAME : target, origin); | |||||
urlEntry = SphU.entry(target, EntryType.IN); | urlEntry = SphU.entry(target, EntryType.IN); | ||||
// Add method specification if necessary | // Add method specification if necessary | ||||
if (httpMethodSpecify) { | if (httpMethodSpecify) { | ||||
@@ -19,6 +19,7 @@ import java.util.Collections; | |||||
import javax.servlet.http.HttpServletRequest; | import javax.servlet.http.HttpServletRequest; | ||||
import com.alibaba.csp.sentinel.Constants; | |||||
import com.alibaba.csp.sentinel.adapter.servlet.callback.DefaultUrlCleaner; | import com.alibaba.csp.sentinel.adapter.servlet.callback.DefaultUrlCleaner; | ||||
import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser; | import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser; | ||||
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner; | import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner; | ||||
@@ -26,6 +27,8 @@ import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager; | |||||
import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig; | import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig; | ||||
import com.alibaba.csp.sentinel.adapter.servlet.util.FilterUtil; | import com.alibaba.csp.sentinel.adapter.servlet.util.FilterUtil; | ||||
import com.alibaba.csp.sentinel.node.ClusterNode; | import com.alibaba.csp.sentinel.node.ClusterNode; | ||||
import com.alibaba.csp.sentinel.node.EntranceNode; | |||||
import com.alibaba.csp.sentinel.node.Node; | |||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant; | import com.alibaba.csp.sentinel.slots.block.RuleConstant; | ||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; | import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; | ||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; | import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; | ||||
@@ -43,7 +46,7 @@ import org.springframework.test.context.junit4.SpringRunner; | |||||
import org.springframework.test.web.servlet.MockMvc; | import org.springframework.test.web.servlet.MockMvc; | ||||
import static org.junit.Assert.*; | import static org.junit.Assert.*; | ||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; | |||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; | |||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; | ||||
/** | /** | ||||
@@ -76,6 +79,7 @@ public class CommonFilterTest { | |||||
@Test | @Test | ||||
public void testCommonFilterMiscellaneous() throws Exception { | public void testCommonFilterMiscellaneous() throws Exception { | ||||
Constants.ROOT.removeChildList(); | |||||
String url = "/hello"; | String url = "/hello"; | ||||
this.mvc.perform(get(url)) | this.mvc.perform(get(url)) | ||||
.andExpect(status().isOk()) | .andExpect(status().isOk()) | ||||
@@ -85,6 +89,17 @@ public class CommonFilterTest { | |||||
assertNotNull(cn); | assertNotNull(cn); | ||||
assertEquals(1, cn.passQps(), 0.01); | assertEquals(1, cn.passQps(), 0.01); | ||||
String context = ""; | |||||
for (Node n : Constants.ROOT.getChildList()) { | |||||
if (n instanceof EntranceNode) { | |||||
String id = ((EntranceNode) n).getId().getName(); | |||||
if (url.equals(id)) { | |||||
context = ((EntranceNode) n).getId().getName(); | |||||
} | |||||
} | |||||
} | |||||
assertEquals("", context); | |||||
testCommonBlockAndRedirectBlockPage(url, cn); | testCommonBlockAndRedirectBlockPage(url, cn); | ||||
// Test for url cleaner. | // Test for url cleaner. | ||||
@@ -0,0 +1,100 @@ | |||||
/* | |||||
* Copyright 1999-2018 Alibaba Group Holding Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||||
* you may not use this file except in compliance with the License. | |||||
* You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
*/ | |||||
package com.alibaba.csp.sentinel.adapter.servletcontext; | |||||
import com.alibaba.csp.sentinel.Constants; | |||||
import com.alibaba.csp.sentinel.node.ClusterNode; | |||||
import com.alibaba.csp.sentinel.node.EntranceNode; | |||||
import com.alibaba.csp.sentinel.node.Node; | |||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant; | |||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; | |||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; | |||||
import com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot; | |||||
import com.alibaba.csp.sentinel.util.StringUtil; | |||||
import org.junit.After; | |||||
import org.junit.Test; | |||||
import org.junit.runner.RunWith; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; | |||||
import org.springframework.boot.test.context.SpringBootTest; | |||||
import org.springframework.test.context.junit4.SpringRunner; | |||||
import org.springframework.test.web.servlet.MockMvc; | |||||
import java.util.Collections; | |||||
import static org.junit.Assert.assertEquals; | |||||
import static org.junit.Assert.assertNotNull; | |||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; | |||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; | |||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | |||||
/** | |||||
* @author zhaoyuguang | |||||
*/ | |||||
@RunWith(SpringRunner.class) | |||||
@SpringBootTest(classes = TestContextApplication.class, | |||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) | |||||
@AutoConfigureMockMvc | |||||
public class CommonFilterContextTest { | |||||
private static final String HELLO_STR = "Hello!"; | |||||
@Autowired | |||||
private MockMvc mvc; | |||||
private void configureRulesFor(String resource, int count) { | |||||
configureRulesFor(resource, count, "default"); | |||||
} | |||||
private void configureRulesFor(String resource, int count, String limitApp) { | |||||
FlowRule rule = new FlowRule() | |||||
.setCount(count) | |||||
.setGrade(RuleConstant.FLOW_GRADE_QPS); | |||||
rule.setResource(resource); | |||||
if (StringUtil.isNotBlank(limitApp)) { | |||||
rule.setLimitApp(limitApp); | |||||
} | |||||
FlowRuleManager.loadRules(Collections.singletonList(rule)); | |||||
} | |||||
@Test | |||||
public void testCommonFilterMiscellaneous() throws Exception { | |||||
String url = "/hello"; | |||||
this.mvc.perform(get(url)) | |||||
.andExpect(status().isOk()) | |||||
.andExpect(content().string(HELLO_STR)); | |||||
ClusterNode cn = ClusterBuilderSlot.getClusterNode(url); | |||||
assertNotNull(cn); | |||||
assertEquals(1, cn.passQps(), 0.01); | |||||
String context = ""; | |||||
for (Node n : Constants.ROOT.getChildList()) { | |||||
if (n instanceof EntranceNode) { | |||||
String id = ((EntranceNode) n).getId().getName(); | |||||
if (url.equals(id)) { | |||||
context = ((EntranceNode) n).getId().getName(); | |||||
} | |||||
} | |||||
} | |||||
assertEquals(url, context); | |||||
} | |||||
@After | |||||
public void cleanUp() { | |||||
FlowRuleManager.loadRules(null); | |||||
ClusterBuilderSlot.resetClusterNodes(); | |||||
} | |||||
} |
@@ -0,0 +1,40 @@ | |||||
/* | |||||
* Copyright 1999-2018 Alibaba Group Holding Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||||
* you may not use this file except in compliance with the License. | |||||
* You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
*/ | |||||
package com.alibaba.csp.sentinel.adapter.servletcontext; | |||||
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter; | |||||
import org.springframework.boot.web.servlet.FilterRegistrationBean; | |||||
import org.springframework.context.annotation.Bean; | |||||
import org.springframework.context.annotation.Configuration; | |||||
/** | |||||
* @author zhaoyuguang | |||||
*/ | |||||
@Configuration | |||||
public class FilterContextConfig { | |||||
@Bean | |||||
public FilterRegistrationBean sentinelFilterRegistration() { | |||||
FilterRegistrationBean registration = new FilterRegistrationBean(); | |||||
registration.setFilter(new CommonFilter()); | |||||
registration.addUrlPatterns("/*"); | |||||
registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false"); | |||||
registration.setName("sentinelFilter"); | |||||
registration.setOrder(1); | |||||
return registration; | |||||
} | |||||
} |
@@ -0,0 +1,30 @@ | |||||
/* | |||||
* Copyright 1999-2018 Alibaba Group Holding Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||||
* you may not use this file except in compliance with the License. | |||||
* You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
*/ | |||||
package com.alibaba.csp.sentinel.adapter.servletcontext; | |||||
import org.springframework.boot.SpringApplication; | |||||
import org.springframework.boot.autoconfigure.SpringBootApplication; | |||||
/** | |||||
* @author zhaoyuguang | |||||
*/ | |||||
@SpringBootApplication | |||||
public class TestContextApplication { | |||||
public static void main(String[] args) { | |||||
SpringApplication.run(TestContextApplication.class, args); | |||||
} | |||||
} |
@@ -0,0 +1,31 @@ | |||||
/* | |||||
* Copyright 1999-2018 Alibaba Group Holding Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||||
* you may not use this file except in compliance with the License. | |||||
* You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
*/ | |||||
package com.alibaba.csp.sentinel.adapter.servletcontext; | |||||
import org.springframework.web.bind.annotation.GetMapping; | |||||
import org.springframework.web.bind.annotation.RestController; | |||||
/** | |||||
* @author zhaoyuguang | |||||
*/ | |||||
@RestController | |||||
public class TestContextController { | |||||
@GetMapping("/hello") | |||||
public String apiHello() { | |||||
return "Hello!"; | |||||
} | |||||
} |