Signed-off-by: Eric Zhao <sczyh16@gmail.com>master
@@ -1,6 +1,7 @@ | |||
# Sentinel Web Servlet Filter | |||
Sentinel provides Servlet filter integration to enable flow control for web requests. Add the following dependency in `pom.xml` (if you are using Maven): | |||
Sentinel provides Servlet filter integration to enable flow control for web requests. | |||
Add the following dependency in `pom.xml` (if you are using Maven): | |||
```xml | |||
<dependency> | |||
@@ -10,7 +11,7 @@ Sentinel provides Servlet filter integration to enable flow control for web requ | |||
</dependency> | |||
``` | |||
To use the filter, you can simply configure your `web.xml` with: | |||
To activate the filter, you can simply configure your `web.xml` with: | |||
```xml | |||
<filter> | |||
@@ -34,8 +35,9 @@ public class FilterConfig { | |||
public FilterRegistrationBean sentinelFilterRegistration() { | |||
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>(); | |||
registration.setFilter(new CommonFilter()); | |||
// Set the matching URL pattern for the filter. | |||
registration.addUrlPatterns("/*"); | |||
registration.setName("sentinelFilter"); | |||
registration.setName("sentinelCommonFilter"); | |||
registration.setOrder(1); | |||
return registration; | |||
@@ -43,7 +45,7 @@ public class FilterConfig { | |||
} | |||
``` | |||
When a request is blocked, Sentinel servlet filter will give a default page indicating the request blocked. | |||
When a request is blocked, Sentinel servlet filter will display a default page indicating the request is rejected. | |||
If customized block page is set (via `WebServletConfig.setBlockPage(blockPage)` method), | |||
the filter will redirect the request to provided URL. You can also implement your own | |||
block handler (the `UrlBlockHandler` interface) and register to `WebCallbackManager`. | |||
@@ -51,8 +53,10 @@ block handler (the `UrlBlockHandler` interface) and register to `WebCallbackMana | |||
The `UrlCleaner` interface is designed for clean and unify the URL resource. | |||
For REST APIs, you have to clean the URL resource (e.g. `/foo/1` and `/foo/2` -> `/foo/:id`), or | |||
the amount of context and resources will exceed the threshold. | |||
The `UrlCleaner` interface can also exclude unused URLs(e.g. `/exclude/1` -> `/exclude/:id` -> `""`). | |||
The URLs will be filtered and not be resource in this way. | |||
If you need to exclude some URLs (that should not be recorded as Sentinel resources), you could also | |||
leverage the `UrlCleaner` interface. You may unify the unwanted URLs to the empty string `""`, | |||
then the URLs will be excluded (since Sentinel 1.6.3). | |||
`RequestOriginParser` interface is useful for extracting request origin (e.g. IP or appName from HTTP Header) | |||
from HTTP request. You can implement your own `RequestOriginParser` and register to `WebCallbackManager`. |
@@ -33,6 +33,7 @@ import com.alibaba.csp.sentinel.Tracer; | |||
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.WebCallbackManager; | |||
import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig; | |||
import com.alibaba.csp.sentinel.adapter.servlet.util.FilterUtil; | |||
import com.alibaba.csp.sentinel.context.ContextUtil; | |||
import com.alibaba.csp.sentinel.slots.block.BlockException; | |||
@@ -59,9 +60,8 @@ public class CommonFilter implements Filter { | |||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) | |||
throws IOException, ServletException { | |||
HttpServletRequest sRequest = (HttpServletRequest) request; | |||
Entry entry = null; | |||
Entry methodEntry = null; | |||
Entry urlEntry = null; | |||
Entry httpMethodUrlEntry = null; | |||
try { | |||
String target = FilterUtil.filterTarget(sRequest); | |||
@@ -78,11 +78,11 @@ public class CommonFilter implements Filter { | |||
if (!StringUtil.isEmpty(target)) { | |||
// Parse the request origin using registered origin parser. | |||
String origin = parseOrigin(sRequest); | |||
ContextUtil.enter(target, origin); | |||
entry = SphU.entry(target, EntryType.IN); | |||
ContextUtil.enter(WebServletConfig.WEB_SERVLET_CONTEXT_NAME, origin); | |||
urlEntry = SphU.entry(target, EntryType.IN); | |||
// Add method specification if necessary | |||
if (httpMethodSpecify) { | |||
methodEntry = SphU.entry(sRequest.getMethod().toUpperCase() + COLON + target, | |||
httpMethodUrlEntry = SphU.entry(sRequest.getMethod().toUpperCase() + COLON + target, | |||
EntryType.IN); | |||
} | |||
} | |||
@@ -91,21 +91,16 @@ public class CommonFilter implements Filter { | |||
HttpServletResponse sResponse = (HttpServletResponse) response; | |||
// Return the block page, or redirect to another URL. | |||
WebCallbackManager.getUrlBlockHandler().blocked(sRequest, sResponse, e); | |||
} catch (IOException e2) { | |||
Tracer.trace(e2); | |||
} catch (IOException | ServletException | RuntimeException e2) { | |||
Tracer.traceEntry(e2, urlEntry); | |||
Tracer.traceEntry(e2, httpMethodUrlEntry); | |||
throw e2; | |||
} catch (ServletException e3) { | |||
Tracer.trace(e3); | |||
throw e3; | |||
} catch (RuntimeException e4) { | |||
Tracer.trace(e4); | |||
throw e4; | |||
} finally { | |||
if (methodEntry != null) { | |||
methodEntry.exit(); | |||
if (httpMethodUrlEntry != null) { | |||
httpMethodUrlEntry.exit(); | |||
} | |||
if (entry != null) { | |||
entry.exit(); | |||
if (urlEntry != null) { | |||
urlEntry.exit(); | |||
} | |||
ContextUtil.exit(); | |||
} | |||
@@ -30,6 +30,7 @@ import com.alibaba.csp.sentinel.Entry; | |||
import com.alibaba.csp.sentinel.SphU; | |||
import com.alibaba.csp.sentinel.Tracer; | |||
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.util.FilterUtil; | |||
import com.alibaba.csp.sentinel.context.ContextUtil; | |||
import com.alibaba.csp.sentinel.slots.block.BlockException; | |||
@@ -52,26 +53,18 @@ public class CommonTotalFilter implements Filter { | |||
public void doFilter(ServletRequest request, ServletResponse response, | |||
FilterChain chain) throws IOException, ServletException { | |||
HttpServletRequest sRequest = (HttpServletRequest)request; | |||
String target = FilterUtil.filterTarget(sRequest); | |||
target = WebCallbackManager.getUrlCleaner().clean(target); | |||
Entry entry = null; | |||
try { | |||
ContextUtil.enter(target); | |||
ContextUtil.enter(WebServletConfig.WEB_SERVLET_CONTEXT_NAME); | |||
entry = SphU.entry(TOTAL_URL_REQUEST); | |||
chain.doFilter(request, response); | |||
} catch (BlockException e) { | |||
HttpServletResponse sResponse = (HttpServletResponse)response; | |||
WebCallbackManager.getUrlBlockHandler().blocked(sRequest, sResponse, e); | |||
} catch (IOException e2) { | |||
} catch (IOException | ServletException | RuntimeException e2) { | |||
Tracer.trace(e2); | |||
throw e2; | |||
} catch (ServletException e3) { | |||
Tracer.trace(e3); | |||
throw e3; | |||
} catch (RuntimeException e4) { | |||
Tracer.trace(e4); | |||
throw e4; | |||
} finally { | |||
if (entry != null) { | |||
entry.exit(); | |||
@@ -24,6 +24,8 @@ import com.alibaba.csp.sentinel.config.SentinelConfig; | |||
*/ | |||
public class WebServletConfig { | |||
public static final String WEB_SERVLET_CONTEXT_NAME = "sentinel_web_servlet_context"; | |||
public static final String BLOCK_PAGE = "csp.sentinel.web.servlet.block.page"; | |||
/** | |||