Signed-off-by: Eric Zhao <sczyh16@gmail.com>master
@@ -39,7 +39,7 @@ public class FilterConfig { | |||
registration.addUrlPatterns("/*"); | |||
registration.setName("sentinelCommonFilter"); | |||
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"); | |||
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. | |||
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), | |||
the filter will redirect the request to provided URL. You can also implement your own | |||
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`, | |||
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`. |
@@ -39,21 +39,30 @@ import com.alibaba.csp.sentinel.context.ContextUtil; | |||
import com.alibaba.csp.sentinel.slots.block.BlockException; | |||
import com.alibaba.csp.sentinel.util.StringUtil; | |||
/*** | |||
/** | |||
* Servlet filter that integrates with Sentinel. | |||
* | |||
* @author zhaoyuguang | |||
* @author youji.zj | |||
* @author Eric Zhao | |||
* @author zhaoyuguang | |||
*/ | |||
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 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 final static String WEB_CONTEXT_UNIFY = "WEB_CONTEXT_UNIFY"; | |||
public static final String WEB_CONTEXT_UNIFY = "WEB_CONTEXT_UNIFY"; | |||
private final static String COLON = ":"; | |||
private boolean httpMethodSpecify = false; | |||
private boolean webContextUnify = true; | |||
@@ -87,7 +96,8 @@ public class CommonFilter implements Filter { | |||
if (!StringUtil.isEmpty(target)) { | |||
// Parse the request origin using registered origin parser. | |||
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); | |||
// Add method specification if necessary | |||
if (httpMethodSpecify) { | |||
@@ -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.CommonTotalFilter; | |||
import com.alibaba.csp.sentinel.config.SentinelConfig; | |||
import com.alibaba.csp.sentinel.log.RecordLog; | |||
import com.alibaba.csp.sentinel.util.StringUtil; | |||
/** | |||
* @author zhaoyuguang | |||
* The configuration center for Web Servlet adapter. | |||
* | |||
* @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 BLOCK_PAGE = "csp.sentinel.web.servlet.block.page"; | |||
public static final String BLOCK_PAGE_HTTP_STATUS = "csp.sentinel.web.servlet.block.page.http.status"; | |||
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"; | |||
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. | |||
*/ | |||
public static String getBlockPage() { | |||
return SentinelConfig.getConfig(BLOCK_PAGE); | |||
return SentinelConfig.getConfig(BLOCK_PAGE_URL_CONF_KEY); | |||
} | |||
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, | |||
* you can use -Dcsp.sentinel.web.servlet.block.page.http.status=200 or other http status, | |||
* to set http status which you want of the default block page. | |||
* When csp.sentinel.web.servlet.block.page.http.status is empty or not number, | |||
* the block page http status will be automatically set to 429(Too Many Requests). | |||
* <p>Get the HTTP status when using the default block page.</p> | |||
* <p>You can set the status code with the {@code -Dcsp.sentinel.web.servlet.block.status} | |||
* property. When the property is empty or invalid, Sentinel will use 429 (Too Many Requests) | |||
* as the default status code.</p> | |||
* | |||
* @return block page http status | |||
* @return the HTTP status of the default block page | |||
* @since 1.7.0 | |||
*/ | |||
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)) { | |||
setBlockPageHttpStatus(HTTP_STATUS_TOO_MANY_REQUESTS); | |||
return HTTP_STATUS_TOO_MANY_REQUESTS; | |||
} | |||
try { | |||
return Integer.parseInt(SentinelConfig.getConfig(BLOCK_PAGE_HTTP_STATUS)); | |||
} catch (NumberFormatException e) { | |||
int s = Integer.parseInt(value); | |||
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); | |||
} | |||
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) { | |||
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() {} | |||
} |