From 9d514d50365e4a9c8b4d6cb7d525e9cbc49c5364 Mon Sep 17 00:00:00 2001 From: Eric Zhao Date: Wed, 6 Nov 2019 15:28:37 +0800 Subject: [PATCH] Improve CommonFilter and WebServletConfig in Sentinel Web Servlet adapter Signed-off-by: Eric Zhao --- .../sentinel-web-servlet/README.md | 7 ++- .../adapter/servlet/CommonFilter.java | 22 +++++--- .../servlet/config/WebServletConfig.java | 53 ++++++++++++------- 3 files changed, 56 insertions(+), 26 deletions(-) diff --git a/sentinel-adapter/sentinel-web-servlet/README.md b/sentinel-adapter/sentinel-web-servlet/README.md index bb7362a8..1d56d21b 100755 --- a/sentinel-adapter/sentinel-web-servlet/README.md +++ b/sentinel-adapter/sentinel-web-servlet/README.md @@ -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`. diff --git a/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilter.java b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilter.java index c50c85ea..bb8f5624 100755 --- a/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilter.java +++ b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/CommonFilter.java @@ -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) { diff --git a/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/config/WebServletConfig.java b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/config/WebServletConfig.java index f6bcd222..dc6f66c4 100755 --- a/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/config/WebServletConfig.java +++ b/sentinel-adapter/sentinel-web-servlet/src/main/java/com/alibaba/csp/sentinel/adapter/servlet/config/WebServletConfig.java @@ -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). + *

Get the HTTP status when using the default block page.

+ *

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.

* - * @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() {} }