es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo enviar una porción de las solicitudes a otra URL

Tengo un servicio web que maneja las solicitudes HTTP GET/POST/PUT utilizando un controlador Spring Rest (usando Netty en lugar de Apache Tomcat). Deseo filtrar todas las solicitudes que llegan a mi servicio, y cuando una solicitud tiene una cierta cabecera configurada, quiero enviar esta solicitud específica a una URL completamente diferente, al mismo tiempo que devuelvo la respuesta a la misma entidad que envió la solicitud original.

Aquí está mi código:

@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("Redirigiendo solicitud con URI {} a algún servicio", 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);
}
}

Con esta implementación, la solicitud simplemente se pasa al controlador rest normal y no llega al otro servicio. ¿Qué me falta aquí?

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Basándose en el código proporcionado, parece que el filtro está interceptando correctamente las solicitudes y comprobando si contienen el encabezado especificado. Si el encabezado está presente y cumple la condición de someService.askSomething(), entonces el código crea una nueva URI y una nueva solicitud utilizando serverWebExchange.getRequest().mutate().uri(someUri).build() y la pasa al webFilterChain para continuar el procesamiento.

    Sin embargo, no está claro dónde exactamente se envía la solicitud a la nueva URI. El código solo está creando una nueva solicitud, pero parece que está pasando la solicitud al webFilterChain sin enviarla realmente a la nueva URI.

    Para enviar la solicitud a la nueva URI, es necesario usar un cliente para hacer una nueva solicitud a la nueva URI con los encabezados y cuerpo de la solicitud modificados, y luego devolver la respuesta a la entidad de solicitud original. Puede utilizar Netty WebClient para hacer una nueva solicitud.

    Aquí hay una implementación actualizada que utiliza Netty WebClient para manejar la solicitud y respuesta:

    @Component
    public class MyWebFilter implements WebFilter {
    
        @Autowired
        private SomeService someService;
        private final Logger log = LoggerFactory.getLogger(MyWebFilter.class);
        private final WebClient webClient = WebClient.create();
    
        @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("Redirigiendo solicitud con URI {} a algún servicio", 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();
                        return webClient.method(serverWebExchange.getRequest().getMethod())
                                .uri(someUri)
                                .headers(httpHeaders -> httpHeaders.addAll(newRequest.getHeaders()))
                                .body(BodyInserters.fromDataBuffers(serverWebExchange.getRequest().getBody()))
                                .exchange()
                                .flatMap(clientResponse -> {
                                    HttpHeaders responseHeaders = new HttpHeaders();
                                    responseHeaders.addAll(clientResponse.headers().asHttpHeaders());
                                    return serverWebExchange.getResponse().writeWith(clientResponse.body(BodyExtractors.toDataBuffers()))
                                            .doOnSuccess(aVoid -> log.info("Respuesta enviada exitosamente"))
                                            .doOnError(Throwable::printStackTrace);
                                });
                    } catch (URISyntaxException e) {
                        throw new IllegalStateException(e.getMessage(), e);
                    }
                }
            }
            return webFilterChain.filter(serverWebExchange);
        }
    }
    

    En esta implementación, se utiliza Netty WebClient para crear una nueva solicitud con la URI y los encabezados modificados, y el cuerpo de la solicitud original. Luego, se utiliza el ClientResponse resultante para escribir la respuesta de vuelta al ServerWebExchange original.

Comments are closed.