Improve CommonFilter and WebServletConfig in Sentinel Web Servlet adapter

Signed-off-by: Eric Zhao <sczyh16@gmail.com>
This commit is contained in:
Eric Zhao 2019-11-06 15:28:37 +08:00
parent b6c2979cee
commit 9d514d5036
3 changed files with 56 additions and 26 deletions

View File

@ -39,7 +39,7 @@ public class FilterConfig {
registration.addUrlPatterns("/*"); registration.addUrlPatterns("/*");
registration.setName("sentinelCommonFilter"); registration.setName("sentinelCommonFilter");
registration.setOrder(1); registration.setOrder(1);
// Set whether to support the specified HTTP method for the filter. // Set whether to support the specified HTTP method prefix for the filter.
registration.addInitParameter(CommonFilter.HTTP_METHOD_SPECIFY, "false"); registration.addInitParameter(CommonFilter.HTTP_METHOD_SPECIFY, "false");
return registration; return registration;
} }
@ -47,6 +47,9 @@ public class FilterConfig {
``` ```
When a request is blocked, Sentinel servlet filter will display a default page indicating the request is rejected. When a request is blocked, Sentinel servlet filter will display a default page indicating the request is rejected.
The HTTP status code of the default block page is **429 (Too Many Requests)**. You can customize it
via the `csp.sentinel.web.servlet.block.status` configuration item (since 1.7.0).
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`.
@ -59,5 +62,5 @@ If you need to exclude some URLs (that should not be recorded as Sentinel resour
leverage the `UrlCleaner` interface. You may unify the unwanted URLs to the empty string `""` or `null`, leverage the `UrlCleaner` interface. You may unify the unwanted URLs to the empty string `""` or `null`,
then the URLs will be excluded (since Sentinel 1.6.3). 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) The `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`.

View File

@ -39,21 +39,30 @@ import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.util.StringUtil; 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
* @author zhaoyuguang
*/ */
public class CommonFilter implements Filter { public class CommonFilter implements Filter {
public 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 * Specify whether the URL resource name should contain the HTTP method prefix (e.g. {@code POST:}).
*/ */
public final static String WEB_CONTEXT_UNIFY = "WEB_CONTEXT_UNIFY"; public static final String HTTP_METHOD_SPECIFY = "HTTP_METHOD_SPECIFY";
/**
* If enabled, use the URL path as the context name, or else use the default
* {@link WebServletConfig#WEB_SERVLET_CONTEXT_NAME}. Please pay attention to the number of context (EntranceNode),
* which may affect the memory footprint.
*
* @since 1.7.0
*/
public static final 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; private boolean webContextUnify = true;
@ -87,7 +96,8 @@ 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(webContextUnify ? WebServletConfig.WEB_SERVLET_CONTEXT_NAME : target, origin); String contextName = webContextUnify ? WebServletConfig.WEB_SERVLET_CONTEXT_NAME : target;
ContextUtil.enter(contextName, 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) {

View File

@ -18,19 +18,21 @@ package com.alibaba.csp.sentinel.adapter.servlet.config;
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter; import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import com.alibaba.csp.sentinel.adapter.servlet.CommonTotalFilter; import com.alibaba.csp.sentinel.adapter.servlet.CommonTotalFilter;
import com.alibaba.csp.sentinel.config.SentinelConfig; import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.util.StringUtil;
/** /**
* @author zhaoyuguang * The configuration center for Web Servlet adapter.
*
* @author leyou * @author leyou
* @author zhaoyuguang
*/ */
public class WebServletConfig { public final class WebServletConfig {
public static final String WEB_SERVLET_CONTEXT_NAME = "sentinel_web_servlet_context"; 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_URL_CONF_KEY = "csp.sentinel.web.servlet.block.page";
public static final String BLOCK_PAGE_HTTP_STATUS_CONF_KEY = "csp.sentinel.web.servlet.block.status";
public static final String BLOCK_PAGE_HTTP_STATUS = "csp.sentinel.web.servlet.block.page.http.status";
private static final int HTTP_STATUS_TOO_MANY_REQUESTS = 429; private static final int HTTP_STATUS_TOO_MANY_REQUESTS = 429;
@ -41,37 +43,52 @@ public class WebServletConfig {
* @return the block page URL, maybe null if not configured. * @return the block page URL, maybe null if not configured.
*/ */
public static String getBlockPage() { public static String getBlockPage() {
return SentinelConfig.getConfig(BLOCK_PAGE); return SentinelConfig.getConfig(BLOCK_PAGE_URL_CONF_KEY);
} }
public static void setBlockPage(String blockPage) { public static void setBlockPage(String blockPage) {
SentinelConfig.setConfig(BLOCK_PAGE, blockPage); SentinelConfig.setConfig(BLOCK_PAGE_URL_CONF_KEY, blockPage);
} }
/** /**
* Return status 429 in the default block page, * <p>Get the HTTP status when using the default block page.</p>
* you can use -Dcsp.sentinel.web.servlet.block.page.http.status=200 or other http status, * <p>You can set the status code with the {@code -Dcsp.sentinel.web.servlet.block.status}
* to set http status which you want of the default block page. * property. When the property is empty or invalid, Sentinel will use 429 (Too Many Requests)
* When csp.sentinel.web.servlet.block.page.http.status is empty or not number, * as the default status code.</p>
* the block page http status will be automatically set to 429(Too Many Requests).
* *
* @return block page http status * @return the HTTP status of the default block page
* @since 1.7.0
*/ */
public static int getBlockPageHttpStatus() { public static int getBlockPageHttpStatus() {
String value = SentinelConfig.getConfig(BLOCK_PAGE_HTTP_STATUS); String value = SentinelConfig.getConfig(BLOCK_PAGE_HTTP_STATUS_CONF_KEY);
if (StringUtil.isEmpty(value)) { if (StringUtil.isEmpty(value)) {
setBlockPageHttpStatus(HTTP_STATUS_TOO_MANY_REQUESTS);
return HTTP_STATUS_TOO_MANY_REQUESTS; return HTTP_STATUS_TOO_MANY_REQUESTS;
} }
try { try {
return Integer.parseInt(SentinelConfig.getConfig(BLOCK_PAGE_HTTP_STATUS)); int s = Integer.parseInt(value);
} catch (NumberFormatException e) { if (s <= 0) {
throw new IllegalArgumentException("Invalid status code: " + s);
}
return s;
} catch (Exception e) {
RecordLog.warn("[WebServletConfig] Invalid block HTTP status (" + value + "), using default 429");
setBlockPageHttpStatus(HTTP_STATUS_TOO_MANY_REQUESTS); setBlockPageHttpStatus(HTTP_STATUS_TOO_MANY_REQUESTS);
} }
return HTTP_STATUS_TOO_MANY_REQUESTS; return HTTP_STATUS_TOO_MANY_REQUESTS;
} }
/**
* Set the HTTP status of the default block page.
*
* @param httpStatus the HTTP status of the default block page
* @since 1.7.0
*/
public static void setBlockPageHttpStatus(int httpStatus) { public static void setBlockPageHttpStatus(int httpStatus) {
SentinelConfig.setConfig(BLOCK_PAGE_HTTP_STATUS, String.valueOf(httpStatus)); if (httpStatus <= 0) {
throw new IllegalArgumentException("Invalid HTTP status code: " + httpStatus);
} }
SentinelConfig.setConfig(BLOCK_PAGE_HTTP_STATUS_CONF_KEY, String.valueOf(httpStatus));
}
private WebServletConfig() {}
} }