* Return canonical status 429 in the default block handler of sentinel-web-servlet-adapter. * Add a `csp.sentinel.web.servlet.block.page.http.status` property to support customized block status configuration.master
@@ -18,8 +18,10 @@ 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.util.StringUtil; | |||
/** | |||
* @author zhaoyuguang | |||
* @author leyou | |||
*/ | |||
public class WebServletConfig { | |||
@@ -28,6 +30,10 @@ public class WebServletConfig { | |||
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"; | |||
private static final int HTTP_STATUS_TOO_MANY_REQUESTS = 429; | |||
/** | |||
* Get redirecting page when Sentinel blocking for {@link CommonFilter} or | |||
* {@link CommonTotalFilter} occurs. | |||
@@ -41,4 +47,31 @@ public class WebServletConfig { | |||
public static void setBlockPage(String blockPage) { | |||
SentinelConfig.setConfig(BLOCK_PAGE, 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). | |||
* | |||
* @return block page http status | |||
*/ | |||
public static int getBlockPageHttpStatus() { | |||
String value = SentinelConfig.getConfig(BLOCK_PAGE_HTTP_STATUS); | |||
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) { | |||
setBlockPageHttpStatus(HTTP_STATUS_TOO_MANY_REQUESTS); | |||
} | |||
return HTTP_STATUS_TOO_MANY_REQUESTS; | |||
} | |||
public static void setBlockPageHttpStatus(int httpStatus) { | |||
SentinelConfig.setConfig(BLOCK_PAGE_HTTP_STATUS, String.valueOf(httpStatus)); | |||
} | |||
} |
@@ -27,6 +27,7 @@ import com.alibaba.csp.sentinel.util.StringUtil; | |||
/** | |||
* Util class for web servlet filter. | |||
* | |||
* @author zhaoyuguang | |||
* @author youji.zj | |||
* @author Eric Zhao | |||
*/ | |||
@@ -65,7 +66,7 @@ public final class FilterUtil { | |||
} | |||
if (StringUtil.isBlank(WebServletConfig.getBlockPage())) { | |||
writeDefaultBlockedPage(response); | |||
writeDefaultBlockedPage(response, WebServletConfig.getBlockPageHttpStatus()); | |||
} else { | |||
String redirectUrl = WebServletConfig.getBlockPage() + "?http_referer=" + url.toString(); | |||
// Redirect to the customized block page. | |||
@@ -73,7 +74,8 @@ public final class FilterUtil { | |||
} | |||
} | |||
private static void writeDefaultBlockedPage(HttpServletResponse response) throws IOException { | |||
private static void writeDefaultBlockedPage(HttpServletResponse response, int httpStatus) throws IOException { | |||
response.setStatus(httpStatus); | |||
PrintWriter out = response.getWriter(); | |||
out.print(DEFAULT_BLOCK_MSG); | |||
out.flush(); | |||
@@ -41,6 +41,7 @@ import org.junit.runner.RunWith; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; | |||
import org.springframework.boot.test.context.SpringBootTest; | |||
import org.springframework.http.HttpStatus; | |||
import org.springframework.http.MediaType; | |||
import org.springframework.test.context.junit4.SpringRunner; | |||
import org.springframework.test.web.servlet.MockMvc; | |||
@@ -50,6 +51,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder | |||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; | |||
/** | |||
* @author zhaoyuguang | |||
* @author Eric Zhao | |||
*/ | |||
@RunWith(SpringRunner.class) | |||
@@ -111,11 +113,17 @@ public class CommonFilterTest { | |||
private void testCommonBlockAndRedirectBlockPage(String url, ClusterNode cn) throws Exception { | |||
configureRulesFor(url, 0); | |||
// The request will be blocked and response is default block message. | |||
WebServletConfig.setBlockPageHttpStatus(HttpStatus.OK.value()); | |||
this.mvc.perform(get(url).accept(MediaType.TEXT_PLAIN)) | |||
.andExpect(status().isOk()) | |||
.andExpect(content().string(FilterUtil.DEFAULT_BLOCK_MSG)); | |||
assertEquals(1, cn.blockQps(), 0.01); | |||
WebServletConfig.setBlockPageHttpStatus(HttpStatus.TOO_MANY_REQUESTS.value()); | |||
this.mvc.perform(get(url).accept(MediaType.TEXT_PLAIN)) | |||
.andExpect(status().isTooManyRequests()) | |||
.andExpect(content().string(FilterUtil.DEFAULT_BLOCK_MSG)); | |||
// Test for redirect. | |||
String redirectUrl = "http://some-location.com"; | |||
WebServletConfig.setBlockPage(redirectUrl); | |||
@@ -192,7 +200,7 @@ public class CommonFilterTest { | |||
.andExpect(content().string(HELLO_STR)); | |||
// This will be blocked. | |||
this.mvc.perform(get(url).accept(MediaType.TEXT_PLAIN).header(headerName, limitOrigin)) | |||
.andExpect(status().isOk()) | |||
.andExpect(status().isTooManyRequests()) | |||
.andExpect(content().string(FilterUtil.DEFAULT_BLOCK_MSG)); | |||
this.mvc.perform(get(url).accept(MediaType.TEXT_PLAIN)) | |||
.andExpect(status().isOk()) | |||
@@ -41,6 +41,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder | |||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; | |||
/** | |||
* @author zhaoyuguang | |||
* @author Roger Law | |||
*/ | |||
@RunWith(SpringRunner.class) | |||
@@ -107,7 +108,7 @@ public class CommonFilterMethodTest { | |||
configureRulesFor(GET + ":" + url, 0); | |||
// The request will be blocked and response is default block message. | |||
this.mvc.perform(get(url).accept(MediaType.TEXT_PLAIN)) | |||
.andExpect(status().isOk()) | |||
.andExpect(status().isTooManyRequests()) | |||
.andExpect(content().string(FilterUtil.DEFAULT_BLOCK_MSG)); | |||
assertEquals(1, cnGet.blockQps(), 0.01); | |||