Signed-off-by: Eric Zhao <sczyh16@gmail.com>master
@@ -1,6 +1,7 @@ | |||||
# Sentinel Web Servlet Filter | # 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 | ```xml | ||||
<dependency> | <dependency> | ||||
@@ -10,7 +11,7 @@ Sentinel provides Servlet filter integration to enable flow control for web requ | |||||
</dependency> | </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 | ```xml | ||||
<filter> | <filter> | ||||
@@ -34,8 +35,9 @@ public class FilterConfig { | |||||
public FilterRegistrationBean sentinelFilterRegistration() { | public FilterRegistrationBean sentinelFilterRegistration() { | ||||
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>(); | FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>(); | ||||
registration.setFilter(new CommonFilter()); | registration.setFilter(new CommonFilter()); | ||||
// Set the matching URL pattern for the filter. | |||||
registration.addUrlPatterns("/*"); | registration.addUrlPatterns("/*"); | ||||
registration.setName("sentinelFilter"); | |||||
registration.setName("sentinelCommonFilter"); | |||||
registration.setOrder(1); | registration.setOrder(1); | ||||
return registration; | 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), | 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 | the filter will redirect the request to provided URL. You can also implement your own | ||||
block handler (the `UrlBlockHandler` interface) and register to `WebCallbackManager`. | 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. | 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 | 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 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) | `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`. | 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.RequestOriginParser; | ||||
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner; | 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.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.adapter.servlet.util.FilterUtil; | ||||
import com.alibaba.csp.sentinel.context.ContextUtil; | import com.alibaba.csp.sentinel.context.ContextUtil; | ||||
import com.alibaba.csp.sentinel.slots.block.BlockException; | 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) | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) | ||||
throws IOException, ServletException { | throws IOException, ServletException { | ||||
HttpServletRequest sRequest = (HttpServletRequest) request; | HttpServletRequest sRequest = (HttpServletRequest) request; | ||||
Entry entry = null; | |||||
Entry methodEntry = null; | |||||
Entry urlEntry = null; | |||||
Entry httpMethodUrlEntry = null; | |||||
try { | try { | ||||
String target = FilterUtil.filterTarget(sRequest); | String target = FilterUtil.filterTarget(sRequest); | ||||
@@ -78,11 +78,11 @@ 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(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 | // Add method specification if necessary | ||||
if (httpMethodSpecify) { | if (httpMethodSpecify) { | ||||
methodEntry = SphU.entry(sRequest.getMethod().toUpperCase() + COLON + target, | |||||
httpMethodUrlEntry = SphU.entry(sRequest.getMethod().toUpperCase() + COLON + target, | |||||
EntryType.IN); | EntryType.IN); | ||||
} | } | ||||
} | } | ||||
@@ -91,21 +91,16 @@ public class CommonFilter implements Filter { | |||||
HttpServletResponse sResponse = (HttpServletResponse) response; | HttpServletResponse sResponse = (HttpServletResponse) response; | ||||
// Return the block page, or redirect to another URL. | // Return the block page, or redirect to another URL. | ||||
WebCallbackManager.getUrlBlockHandler().blocked(sRequest, sResponse, e); | 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; | throw e2; | ||||
} catch (ServletException e3) { | |||||
Tracer.trace(e3); | |||||
throw e3; | |||||
} catch (RuntimeException e4) { | |||||
Tracer.trace(e4); | |||||
throw e4; | |||||
} finally { | } finally { | ||||
if (methodEntry != null) { | |||||
methodEntry.exit(); | |||||
if (httpMethodUrlEntry != null) { | |||||
httpMethodUrlEntry.exit(); | |||||
} | } | ||||
if (entry != null) { | |||||
entry.exit(); | |||||
if (urlEntry != null) { | |||||
urlEntry.exit(); | |||||
} | } | ||||
ContextUtil.exit(); | ContextUtil.exit(); | ||||
} | } | ||||
@@ -30,6 +30,7 @@ import com.alibaba.csp.sentinel.Entry; | |||||
import com.alibaba.csp.sentinel.SphU; | import com.alibaba.csp.sentinel.SphU; | ||||
import com.alibaba.csp.sentinel.Tracer; | import com.alibaba.csp.sentinel.Tracer; | ||||
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager; | 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.adapter.servlet.util.FilterUtil; | ||||
import com.alibaba.csp.sentinel.context.ContextUtil; | import com.alibaba.csp.sentinel.context.ContextUtil; | ||||
import com.alibaba.csp.sentinel.slots.block.BlockException; | import com.alibaba.csp.sentinel.slots.block.BlockException; | ||||
@@ -52,26 +53,18 @@ public class CommonTotalFilter implements Filter { | |||||
public void doFilter(ServletRequest request, ServletResponse response, | public void doFilter(ServletRequest request, ServletResponse response, | ||||
FilterChain chain) throws IOException, ServletException { | FilterChain chain) throws IOException, ServletException { | ||||
HttpServletRequest sRequest = (HttpServletRequest)request; | HttpServletRequest sRequest = (HttpServletRequest)request; | ||||
String target = FilterUtil.filterTarget(sRequest); | |||||
target = WebCallbackManager.getUrlCleaner().clean(target); | |||||
Entry entry = null; | Entry entry = null; | ||||
try { | try { | ||||
ContextUtil.enter(target); | |||||
ContextUtil.enter(WebServletConfig.WEB_SERVLET_CONTEXT_NAME); | |||||
entry = SphU.entry(TOTAL_URL_REQUEST); | entry = SphU.entry(TOTAL_URL_REQUEST); | ||||
chain.doFilter(request, response); | chain.doFilter(request, response); | ||||
} catch (BlockException e) { | } catch (BlockException e) { | ||||
HttpServletResponse sResponse = (HttpServletResponse)response; | HttpServletResponse sResponse = (HttpServletResponse)response; | ||||
WebCallbackManager.getUrlBlockHandler().blocked(sRequest, sResponse, e); | WebCallbackManager.getUrlBlockHandler().blocked(sRequest, sResponse, e); | ||||
} catch (IOException e2) { | |||||
} catch (IOException | ServletException | RuntimeException e2) { | |||||
Tracer.trace(e2); | Tracer.trace(e2); | ||||
throw e2; | throw e2; | ||||
} catch (ServletException e3) { | |||||
Tracer.trace(e3); | |||||
throw e3; | |||||
} catch (RuntimeException e4) { | |||||
Tracer.trace(e4); | |||||
throw e4; | |||||
} finally { | } finally { | ||||
if (entry != null) { | if (entry != null) { | ||||
entry.exit(); | entry.exit(); | ||||
@@ -24,6 +24,8 @@ import com.alibaba.csp.sentinel.config.SentinelConfig; | |||||
*/ | */ | ||||
public class WebServletConfig { | 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"; | public static final String BLOCK_PAGE = "csp.sentinel.web.servlet.block.page"; | ||||
/** | /** | ||||