@@ -50,7 +50,7 @@ public class WebFluxConfig { | |||
You can register various customized callback in `WebFluxCallbackManager`: | |||
- `setBlockHandler`: register a customized `BlockRequestHandler` to handle the blocked request. The default implementation is `DefaultBlockRequestHandler`, which returns default message like `Blocked by Sentinel: FlowException`. | |||
- `setUrlCleaner`: used for normalization of URL. The function type is `(ServerWebExchange, String) → String`, which means `(webExchange, originalUrl) → finalUrl`. | |||
- `setUrlCleaner`: used for normalization of URL. The function type is `(ServerWebExchange, String) → String`, which means `(webExchange, originalUrl) → finalUrl`, if the finalUrl is `"""` or `null`, the URLs will be excluded (since Sentinel 1.7.0).. | |||
- `setRequestOriginParser`: used to resolve the origin from the HTTP request. The function type is `ServerWebExchange → String`. | |||
You can also refer to the demo: [sentinel-demo-spring-webflux](https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-spring-webflux). |
@@ -22,6 +22,7 @@ import com.alibaba.csp.sentinel.adapter.reactor.ContextConfig; | |||
import com.alibaba.csp.sentinel.adapter.reactor.EntryConfig; | |||
import com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorTransformer; | |||
import com.alibaba.csp.sentinel.adapter.spring.webflux.callback.WebFluxCallbackManager; | |||
import com.alibaba.csp.sentinel.util.StringUtil; | |||
import org.springframework.web.server.ServerWebExchange; | |||
import org.springframework.web.server.WebFilter; | |||
@@ -36,24 +37,23 @@ public class SentinelWebFluxFilter implements WebFilter { | |||
@Override | |||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { | |||
return chain.filter(exchange) | |||
.transform(buildSentinelTransformer(exchange)); | |||
} | |||
private SentinelReactorTransformer<Void> buildSentinelTransformer(ServerWebExchange exchange) { | |||
// Maybe we can get the URL pattern elsewhere via: | |||
// exchange.getAttributeOrDefault(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, path) | |||
String path = exchange.getRequest().getPath().value(); | |||
String finalPath = Optional.ofNullable(WebFluxCallbackManager.getUrlCleaner()) | |||
.map(f -> f.apply(exchange, path)) | |||
.orElse(path); | |||
String finalPath = WebFluxCallbackManager.getUrlCleaner().apply(exchange, path); | |||
if (StringUtil.isEmpty(finalPath)) { | |||
return chain.filter(exchange); | |||
} | |||
return chain.filter(exchange).transform(buildSentinelTransformer(exchange, finalPath)); | |||
} | |||
private SentinelReactorTransformer<Void> buildSentinelTransformer(ServerWebExchange exchange, String finalPath) { | |||
String origin = Optional.ofNullable(WebFluxCallbackManager.getRequestOriginParser()) | |||
.map(f -> f.apply(exchange)) | |||
.orElse(EMPTY_ORIGIN); | |||
return new SentinelReactorTransformer<>( | |||
new EntryConfig(finalPath, EntryType.IN, new ContextConfig(finalPath, origin))); | |||
return new SentinelReactorTransformer<>(new EntryConfig(finalPath, EntryType.IN, new ContextConfig(finalPath, origin))); | |||
} | |||
private static final String EMPTY_ORIGIN = ""; | |||
@@ -101,6 +101,26 @@ public class SentinelWebFluxIntegrationTest { | |||
WebFluxCallbackManager.resetUrlCleaner(); | |||
} | |||
@Test | |||
public void testCustomizedIgnoreUrlCleaner() throws Exception { | |||
final String fooPrefix = "/foo/"; | |||
String url1 = fooPrefix + 1; | |||
WebFluxCallbackManager.setUrlCleaner(((exchange, originUrl) -> { | |||
if (originUrl.startsWith(fooPrefix)) { | |||
return ""; | |||
} | |||
return originUrl; | |||
})); | |||
this.webClient.get() | |||
.uri(url1) | |||
.exchange() | |||
.expectStatus().isOk() | |||
.expectBody(String.class).isEqualTo("Hello 1"); | |||
assertNull(ClusterBuilderSlot.getClusterNode(url1)); | |||
WebFluxCallbackManager.resetUrlCleaner(); | |||
} | |||
@Test | |||
public void testCustomizedBlockRequestHandler() throws Exception { | |||
String url = "/error"; | |||
@@ -166,4 +186,4 @@ public class SentinelWebFluxIntegrationTest { | |||
FlowRuleManager.loadRules(new ArrayList<>()); | |||
ClusterBuilderSlot.resetClusterNodes(); | |||
} | |||
} | |||
} |