I have a web service which handles GET/POST/PUT HTTP requests using a Spring Rest Controller (using Netty and not Apache Tomcat). I wish to filter all the requests coming in my service, and when a request has a certain header configured, I want to send this specific request to a whole different URL, while returning the response to the same entity which sent the original request.
Here is my code:
@Component
public class MyWebFilter implements WebFilter {
@Autowired
private SomeService someService;
private final Logger log = LoggerFactory.getLogger(MyWebFilter.class);
@Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
HttpHeaders headers = serverWebExchange.getRequest().getHeaders();
if (headers.containsKey("someHeader")) {
if (someService.askSomething(Objects.requireNonNull(headers.get("someHeader")))) {
URI originalUri = serverWebExchange.getRequest().getURI();
log.info("Redirecting request with URI {} to some service", originalUri.getPath());
try {
URI someUri = new URI("http",
originalUri.getUserInfo(),
someService.getHost(),
someService.getPort(),
originalUri.getPath(),
originalUri.getQuery(),
originalUri.getFragment());
ServerHttpRequest newRequest = serverWebExchange.getRequest().mutate().uri(someUri).build();
ServerWebExchange newExchange = serverWebExchange.mutate().request(newRequest).build();
return webFilterChain.filter(newExchange);
} catch (URISyntaxException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
}
return webFilterChain.filter(serverWebExchange);
}
}
With this implementation the request is simply passed through to my normal rest controller and does not reach the other service. What am I missing here?
CodePudding user response:
you should add @Order and specify correct order, and then set debug = true to see the filter execution. see also spring webflux webfilters
CodePudding user response:
Eventually I solved this by using Spring's WebClient (https://www.baeldung.com/spring-5-webclient) in order to resend the request to the external service.
@Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
HttpHeaders headers = serverWebExchange.getRequest().getHeaders();
if (headers.containsKey("someHeader")) {
if (someService.askSomething(Objects.requireNonNull(headers.get("someHeader")))) {
URI originalUri = serverWebExchange.getRequest().getURI();
log.info("Redirecting a {} HTTP request with path {} to some service",serverWebExchange.getRequest().getMethod(), originalUri.getPath());
return sendToSomeService(serverWebExchange.getRequest(), originalUri.getPath()).flatMap(body -> writeResponse(serverWebExchange, body));
}
}
return webFilterChain.filter(serverWebExchange);
}
public Mono<String> sendToSomeService(ServerHttpRequest request, String path) {
return this.webClient.method(Objects.requireNonNull(request.getMethod())).uri(path)
.body(BodyInserters.fromDataBuffers(request.getBody()))
.headers(getHttpHeadersConsumer(request))
.retrieve()
.bodyToMono(String.class);
}
@NotNull
private Consumer<HttpHeaders> getHttpHeadersConsumer(ServerHttpRequest request) {
return new Consumer<HttpHeaders>() {
@Override
public void accept(HttpHeaders httpHeaders) {
for (Map.Entry<String, List<String>> header : request.getHeaders().entrySet()) {
httpHeaders.set(header.getKey(), header.getValue().get(0));
}
}
};
}
private Mono<Void> writeResponse(ServerWebExchange exchange, String message) {
exchange.getResponse().getHeaders().add("Content-Type", "application/json");
return exchange
.getResponse()
.writeWith(
Flux.just(
exchange.getResponse().bufferFactory().wrap(message.getBytes(StandardCharsets.UTF_8))));
}