Search code examples
springspring-bootspring-webfluxproject-reactorspring-cloud-gateway

How to get request body in Spring Cloud Gateway and addHeader


I plan to migrate a project from Zuul to Spring Cloud Gateway. I have a "checksum code" and I don't know how to migrate it.

In the zuul code i get the url parameter and json body, I then do some checks.

HttpServletRequest request = requestContext.getRequest();
Map<String, String[]> parameterMap = getURLParamter(request);
String json = getBody(request);

if(securityCheck(parameterMap, json) == true) {
    requestContext.addZuulRequestHeader("check-success-then-next-filter", "1");
} else {
    requestContext.setResponseBody("{ msg:: check error }");
}

I have limited experience with Spring gateway please help me find what the equivalent code is in Spring Gateway,


Solution

  • Spring Cloud gateway has filters to modify request body and response body.

    ModifyResponseBody
    ModifyRequestBody

    As mentioned in the specs, for using these filters, we need to use DSL approach rather than YAML file for configuring routes. So essentially you will have a RouteBuilder like below -

    @Bean
    public RouteLocator myRoutes(RouteLocatorBuilder builder) {
        RouteLocatorBuilder.Builder routeLocator = builder.routes().route(
        p -> {
          p.method("POST").path("/<path>").filters(f -> {
             f.modifyRequestBody(String.class, 
                                 String.class,
                                 (exchange, reqMessage) -> {
                    try {
                        log.info(">>> INCOMING REQUEST <<< - {}", reqMessage);
                        //Get query params
                        exchange.getRequest().getQueryParams();
                        // In case of any validation errors, throw an exception so that 
                        // it can be handled by a global exception handler
                        return Mono.just(reqMessage);
                    } catch (Exception e) {
                        log.error("Exception while modifying request body", e);
                        throw new RuntimeException(e.getMessage());
                    }
                });
            })
        });
    }
    
    

    A global exception handler could then send a standard response back -

    public class GlobalExceptionHandler extends AbstractErrorWebExceptionHandler {
        @Override
        protected RouterFunction<ServerResponse> getRoutingFunction (ErrorAttributes errorAttributes) {
           return RouterFunctions.route(RequestPredicates.all(),this::renderErrorResponse);
        }
        
        private Mono<ServerResponse> renderErrorResponse (ServletRequest request) {
            Map<String,Object> errorPropertiesMap = getErrorAttributes (request,ErrorAttributeOptions.defaults());
            String customErrMsg = errorPropertiesMap.get("message") != null ? errorPropertiesMap.get("message").toString() : null;
        
            if(customErrMsg != null) {
                return ServerResponse.status(HttpStatus.BAD_REQUEST)
                                     .contentType(MediaType.APPLICATION_JSON)
                                     .body(BodyInserters.fromValue(errorPropertiesMap.get("message")));
            } else {
                return ServerResponse.status(HttpStatus.BAD_REQUEST)
                                     .contentType(MediaType.APPLICATION_JSON)
                                     .body(BodyInserters.fromValue(errorPropertiesMap));
            }
        }
    }