@@ -50,7 +50,7 @@ public class WebFluxConfig { | |||||
You can register various customized callback in `WebFluxCallbackManager`: | 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`. | - `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`. | - `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). | 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.EntryConfig; | ||||
import com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorTransformer; | import com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorTransformer; | ||||
import com.alibaba.csp.sentinel.adapter.spring.webflux.callback.WebFluxCallbackManager; | 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.ServerWebExchange; | ||||
import org.springframework.web.server.WebFilter; | import org.springframework.web.server.WebFilter; | ||||
@@ -36,24 +37,23 @@ public class SentinelWebFluxFilter implements WebFilter { | |||||
@Override | @Override | ||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { | 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: | // Maybe we can get the URL pattern elsewhere via: | ||||
// exchange.getAttributeOrDefault(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, path) | // exchange.getAttributeOrDefault(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, path) | ||||
String path = exchange.getRequest().getPath().value(); | 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()) | String origin = Optional.ofNullable(WebFluxCallbackManager.getRequestOriginParser()) | ||||
.map(f -> f.apply(exchange)) | .map(f -> f.apply(exchange)) | ||||
.orElse(EMPTY_ORIGIN); | .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 = ""; | private static final String EMPTY_ORIGIN = ""; | ||||
@@ -101,6 +101,26 @@ public class SentinelWebFluxIntegrationTest { | |||||
WebFluxCallbackManager.resetUrlCleaner(); | 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 | @Test | ||||
public void testCustomizedBlockRequestHandler() throws Exception { | public void testCustomizedBlockRequestHandler() throws Exception { | ||||
String url = "/error"; | String url = "/error"; | ||||
@@ -166,4 +186,4 @@ public class SentinelWebFluxIntegrationTest { | |||||
FlowRuleManager.loadRules(new ArrayList<>()); | FlowRuleManager.loadRules(new ArrayList<>()); | ||||
ClusterBuilderSlot.resetClusterNodes(); | ClusterBuilderSlot.resetClusterNodes(); | ||||
} | } | ||||
} | |||||
} |