Spring-cloud-gateway: How to modify request / response body?

Created on 16 Nov 2017  ·  37Comments  ·  Source: spring-cloud/spring-cloud-gateway

Is it possible?

Most helpful comment

I didn't get how to change the response body. I have a json in the body and I want to add a property to it.

Example config:

spring:
    cloud:
        gateway:
            routes:
              - id: test
                uri: http://jsonplaceholder.typicode.com:80
                predicates:
                  - Path=/**
                filters:
                  - MyFilter

My custom filter:

@Component
class MyFilter : GatewayFilterFactory {
    override fun apply(args: Tuple?): GatewayFilter {
        return GatewayFilter { exchange, chain ->
// I want to add a property to json response body, say, "a": 123. How?
            chain.filter(exchange)
        }
    }
}

I want to add a property to json response body, say, "a": 123. How?

You need to modify the header Content-Length, If you don't do this, the body may be truncated after you have modify the request body and the body becomes longer.

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = (ServerHttpRequest) exchange.getRequest();
String bodyString = getRequestBody(request);
DataBuffer bodyDataBuffer = stringBuffer(bodyString);
int len = bodyDataBuffer.readableByteCount();
URI requestUri = request.getURI();
URI ex = UriComponentsBuilder.fromUri(requestUri).build(true).toUri();
ServerHttpRequest newRequest = request.mutate().uri(ex).build();

    HttpHeaders myHeaders = new HttpHeaders();
    copyMultiValueMap(request.getHeaders(), myHeaders);
    myHeaders.remove(HttpHeaders.CONTENT_LENGTH);
    myHeaders.set(HttpHeaders.CONTENT_LENGTH, String.valueOf(len));

    Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);
    newRequest = new ServerHttpRequestDecorator(newRequest) {
        @Override
        public Flux<DataBuffer> getBody() { 
            return bodyFlux;
        }

        @Override
        public HttpHeaders getHeaders() {
            return myHeaders;               
        }
    };

    ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();

    return chain.filter(newExchange);


    //return chain.filter(exchange);
    //return returnMono(chain, exchange);
}

private static <K, V> void copyMultiValueMap(MultiValueMap<K,V> source, MultiValueMap<K,V> target) {
    source.forEach((key, value) -> target.put(key, new LinkedList<>(value)));
}

private DataBuffer stringBuffer(String value){
    byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
    NettyDataBufferFactory nettyDataBufferFactory = new 
    NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
    DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
    buffer.write(bytes);
    return buffer;
}



private String getRequestBody(ServerHttpRequest request) {
    Flux<DataBuffer> body = request.getBody();
    StringBuilder sb = new StringBuilder();        

    body.subscribe(buffer -> {
        byte[] bytes = new byte[buffer.readableByteCount()];
        buffer.read(bytes);
        DataBufferUtils.release(buffer);
        String bodyString = new String(bytes, StandardCharsets.UTF_8);
        sb.append(bodyString);
    });
    String str = sb.toString();
    if (str != null) {

        try {
            JSONObject obj = new JSONObject(str);
            obj.put("BSN_FLOWNUM", getBsnFlowNum("M1"));
            str = obj.toString();
        }catch(Exception e) {
            log.error(e.getMessage(), e);
        }           
    }        
    return str;
} 

private String getBsnFlowNum(String machineId) {
    Calendar ca = Calendar.getInstance();       
    this.flowNum = (this.flowNum + 1) % 100000;
    String str = String.format("%s%04d%02d%02d%02d%02d%02d%05d", 
            machineId, ca.get(Calendar.YEAR), ca.get(Calendar.MONTH) + 1,
            ca.get(Calendar.DAY_OF_MONTH), ca.get(Calendar.HOUR), ca.get(Calendar.MINUTE),
            ca.get(Calendar.SECOND), this.flowNum);
    return str;
}

All 37 comments

You can use WebFilter, here the README:

  • Filters can modify downstream HTTP Request and HTTP Response (Add/Remove Headers, Add/Remove Parameters, Rewrite Path, Set Path, Hystrix, etc…​)

Here the example how to add request parameter:

.route("addrequestheader_route")
.uri("http://localhost:8080")
.predicate(path("/search"))
.add(addRequestParameter("value1", "value2"))

or

spring:
cloud:
gateway:
routes:
- id: addrequestparameter_route
uri: http://localhost:8080
predicates:
- Path=/search
filters:
- AddRequestParameter=value1, value2

Thank you, but I found how to do that. I don't know whether WebFilter can
be used here, but Spencer uses for it the GatewayFilter.

See the correct example in WeirdBob's closed issue.

25 нояб. 2017 г. 1:25 пользователь "Henrique Amaral" <
[email protected]> написал:

You can use WebFilter, here the README:

  • Filters can modify downstream HTTP Request and HTTP Response
    (Add/Remove Headers, Add/Remove Parameters, Rewrite Path, Set Path,
    Hystrix, etc…​)

Here the example how to add request parameter:

.route("addrequestheader_route")
.uri("http://localhost:8080")
.predicate(path("/search"))
.add(addRequestParameter("value1", "value2"))

or

spring:
cloud:
gateway:
routes:

  • id: addrequestparameter_route
    uri: http://localhost:8080
    predicates:
  • Path=/search
    filters:
  • AddRequestParameter=value1, value2


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/spring-cloud/spring-cloud-gateway/issues/113#issuecomment-346902240,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ACzyA1oVyB9YsVxA3R1D3gbCeJ3WZ-Pwks5s50JYgaJpZM4QgeKW
.

I didn't get how to change the response body. I have a json in the body and I want to add a property to it.

Example config:

spring:
    cloud:
        gateway:
            routes:
              - id: test
                uri: http://jsonplaceholder.typicode.com:80
                predicates:
                  - Path=/**
                filters:
                  - MyFilter

My custom filter:

@Component
class MyFilter : GatewayFilterFactory {
    override fun apply(args: Tuple?): GatewayFilter {
        return GatewayFilter { exchange, chain ->
// I want to add a property to json response body, say, "a": 123. How?
            chain.filter(exchange)
        }
    }
}

I want to add a property to json response body, say, "a": 123. How?

Search an other closed issue by "body" keyword, there is an example from WeirdBob and my additional comment to it.
You can also use an appropriate Decoder to get a map or the object you are interested in.

Thanks. I found the issue you said and it kinda works. The problem is that that filter works for every route (because I'm using @Component I guess), but I'd like to apply it to a specific route through the configuration file as above (.yml, and not through .route().filters()) . How can I do that?

If I remove the @Component and set:

    filters:
      - MyFilter

it says:

Caused by: java.lang.IllegalArgumentException: Unable to find GatewayFilterFactory with name MyFilter

See how Spencer does. There is some builder behind which is responsible for built-in filters creation. Do not use component, you see, it's another model of data flow, not old known MVC.

Ah, you write about configuration file. Sorry. I do not using this approach because of ľd prefer fine tuning. I didn't research this way, not sure.

Keep in mind, it's a quite young project...

Hey guys, is it possible to modify response and return it immediately? for example I'm adding authorization and I want to reject further filtering if user is unauthorized?

Look for an example in closed issues. There is an example from @WeirdBob (post filter implementation).

As I understood from the example this filter will be invoked after request will be processed. I need to return response immediately in case of invalid authentication.

Hey @spencergibb
Thanks for your answer. The main question for me here is how can I modify response body in such case.

@spencergibb
Any thoughts on the question above?
Thanks in advance

@malinovskiy-alex
Why don't you just throw an exception in your filter? you can then implement a WebExceptionHandler to return the response you want (headers & body). Throwing an exception will stop the filtering chain.

That was one of the possible solutions, but I thought that there is some common way to update response body directly.

Also will this solution not brake reactive logic of the cloud api gateway?

I'm no expert but I'd say if you want to stop the filter chain, not route the request because of the authorization, the most logical thing to do is to throw an exception. It doesn't break the reactive logic, in the WebExceptionHandler you still have to return a Mono and you write in the response with a Publisher<> (even if for an error we just write a Mono).
If you want to modify the response after the request has been routed and processed by the downstream server and it's the standard processing of your request, then see the examples linked in the comments of this issue on how to use a filter to decorate the response object.
In our project we use both methods depending on the case: exceptions for all the error handling (authentication, authorization, missing security headers, malformed requests ...), and filters to modify the request/response bodies as part of the standard processing (requests are deciphered, we remove some fields of the responses and recipher them ...)

Ok, thanks for your response. Let me check approach with webexceptionhandler.

It works. Thank you.

I've wrote some API for post processing, now I'm working on pre-processing (it works, but I need do some refactoring). But the work was interrupted for a while. In a week or two I'm going to commit my code after the tests will being written.

I've added post on stackoverflow for that so you can probably add your answer as soon as you finish with refactoring.

not able to read response in cloud gateway in filter

I didn't get how to change the response body. I have a json in the body and I want to add a property to it.

Example config:

spring:
    cloud:
        gateway:
            routes:
              - id: test
                uri: http://jsonplaceholder.typicode.com:80
                predicates:
                  - Path=/**
                filters:
                  - MyFilter

My custom filter:

@Component
class MyFilter : GatewayFilterFactory {
    override fun apply(args: Tuple?): GatewayFilter {
        return GatewayFilter { exchange, chain ->
// I want to add a property to json response body, say, "a": 123. How?
            chain.filter(exchange)
        }
    }
}

I want to add a property to json response body, say, "a": 123. How?

You need to modify the header Content-Length, If you don't do this, the body may be truncated after you have modify the request body and the body becomes longer.

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = (ServerHttpRequest) exchange.getRequest();
String bodyString = getRequestBody(request);
DataBuffer bodyDataBuffer = stringBuffer(bodyString);
int len = bodyDataBuffer.readableByteCount();
URI requestUri = request.getURI();
URI ex = UriComponentsBuilder.fromUri(requestUri).build(true).toUri();
ServerHttpRequest newRequest = request.mutate().uri(ex).build();

    HttpHeaders myHeaders = new HttpHeaders();
    copyMultiValueMap(request.getHeaders(), myHeaders);
    myHeaders.remove(HttpHeaders.CONTENT_LENGTH);
    myHeaders.set(HttpHeaders.CONTENT_LENGTH, String.valueOf(len));

    Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);
    newRequest = new ServerHttpRequestDecorator(newRequest) {
        @Override
        public Flux<DataBuffer> getBody() { 
            return bodyFlux;
        }

        @Override
        public HttpHeaders getHeaders() {
            return myHeaders;               
        }
    };

    ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();

    return chain.filter(newExchange);


    //return chain.filter(exchange);
    //return returnMono(chain, exchange);
}

private static <K, V> void copyMultiValueMap(MultiValueMap<K,V> source, MultiValueMap<K,V> target) {
    source.forEach((key, value) -> target.put(key, new LinkedList<>(value)));
}

private DataBuffer stringBuffer(String value){
    byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
    NettyDataBufferFactory nettyDataBufferFactory = new 
    NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
    DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
    buffer.write(bytes);
    return buffer;
}



private String getRequestBody(ServerHttpRequest request) {
    Flux<DataBuffer> body = request.getBody();
    StringBuilder sb = new StringBuilder();        

    body.subscribe(buffer -> {
        byte[] bytes = new byte[buffer.readableByteCount()];
        buffer.read(bytes);
        DataBufferUtils.release(buffer);
        String bodyString = new String(bytes, StandardCharsets.UTF_8);
        sb.append(bodyString);
    });
    String str = sb.toString();
    if (str != null) {

        try {
            JSONObject obj = new JSONObject(str);
            obj.put("BSN_FLOWNUM", getBsnFlowNum("M1"));
            str = obj.toString();
        }catch(Exception e) {
            log.error(e.getMessage(), e);
        }           
    }        
    return str;
} 

private String getBsnFlowNum(String machineId) {
    Calendar ca = Calendar.getInstance();       
    this.flowNum = (this.flowNum + 1) % 100000;
    String str = String.format("%s%04d%02d%02d%02d%02d%02d%05d", 
            machineId, ca.get(Calendar.YEAR), ca.get(Calendar.MONTH) + 1,
            ca.get(Calendar.DAY_OF_MONTH), ca.get(Calendar.HOUR), ca.get(Calendar.MINUTE),
            ca.get(Calendar.SECOND), this.flowNum);
    return str;
}

I didn't get how to change the response body. I have a json in the body and I want to add a property to it.
Example config:

spring:
    cloud:
        gateway:
            routes:
              - id: test
                uri: http://jsonplaceholder.typicode.com:80
                predicates:
                  - Path=/**
                filters:
                  - MyFilter

My custom filter:

@Component
class MyFilter : GatewayFilterFactory {
    override fun apply(args: Tuple?): GatewayFilter {
        return GatewayFilter { exchange, chain ->
// I want to add a property to json response body, say, "a": 123. How?
            chain.filter(exchange)
        }
    }
}

I want to add a property to json response body, say, "a": 123. How?

You need to modify the header Content-Length, If you don't do this, the body may be truncated after you have modify the request body and the body becomes longer.

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = (ServerHttpRequest) exchange.getRequest();
String bodyString = getRequestBody(request);
DataBuffer bodyDataBuffer = stringBuffer(bodyString);
int len = bodyDataBuffer.readableByteCount();
URI requestUri = request.getURI();
URI ex = UriComponentsBuilder.fromUri(requestUri).build(true).toUri();
ServerHttpRequest newRequest = request.mutate().uri(ex).build();

    HttpHeaders myHeaders = new HttpHeaders();
    copyMultiValueMap(request.getHeaders(), myHeaders);
    myHeaders.remove(HttpHeaders.CONTENT_LENGTH);
    myHeaders.set(HttpHeaders.CONTENT_LENGTH, String.valueOf(len));

    Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);
    newRequest = new ServerHttpRequestDecorator(newRequest) {
        @Override
        public Flux<DataBuffer> getBody() {   
            return bodyFlux;
        }

        @Override
        public HttpHeaders getHeaders() {
          return myHeaders;               
        }
    };

    ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();

    return chain.filter(newExchange);


  //return chain.filter(exchange);
  //return returnMono(chain, exchange);
}

private static <K, V> void copyMultiValueMap(MultiValueMap<K,V> source, MultiValueMap<K,V> target) {
  source.forEach((key, value) -> target.put(key, new LinkedList<>(value)));
}

private DataBuffer stringBuffer(String value){
    byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
    NettyDataBufferFactory nettyDataBufferFactory = new 
    NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
    DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
    buffer.write(bytes);
    return buffer;
}



private String getRequestBody(ServerHttpRequest request) {
    Flux<DataBuffer> body = request.getBody();
    StringBuilder sb = new StringBuilder();        

    body.subscribe(buffer -> {
        byte[] bytes = new byte[buffer.readableByteCount()];
        buffer.read(bytes);
        DataBufferUtils.release(buffer);
        String bodyString = new String(bytes, StandardCharsets.UTF_8);
        sb.append(bodyString);
    });
    String str = sb.toString();
    if (str != null) {

      try {
          JSONObject obj = new JSONObject(str);
          obj.put("BSN_FLOWNUM", getBsnFlowNum("M1"));
          str = obj.toString();
      }catch(Exception e) {
          log.error(e.getMessage(), e);
      }           
    }        
    return str;
} 

private String getBsnFlowNum(String machineId) {
  Calendar ca = Calendar.getInstance();       
  this.flowNum = (this.flowNum + 1) % 100000;
  String str = String.format("%s%04d%02d%02d%02d%02d%02d%05d", 
          machineId, ca.get(Calendar.YEAR), ca.get(Calendar.MONTH) + 1,
          ca.get(Calendar.DAY_OF_MONTH), ca.get(Calendar.HOUR), ca.get(Calendar.MINUTE),
          ca.get(Calendar.SECOND), this.flowNum);
  return str;
}

Thank you very much for your excellent answer. I really appreciate it. This problem troubled me a lot the prior weekend.
-- An IT developer from Shanghai

I didn't get how to change the response body. I have a json in the body and I want to add a property to it.
Example config:

spring:
    cloud:
        gateway:
            routes:
              - id: test
                uri: http://jsonplaceholder.typicode.com:80
                predicates:
                  - Path=/**
                filters:
                  - MyFilter

My custom filter:

@Component
class MyFilter : GatewayFilterFactory {
    override fun apply(args: Tuple?): GatewayFilter {
        return GatewayFilter { exchange, chain ->
// I want to add a property to json response body, say, "a": 123. How?
            chain.filter(exchange)
        }
    }
}

I want to add a property to json response body, say, "a": 123. How?

You need to modify the header Content-Length, If you don't do this, the body may be truncated after you have modify the request body and the body becomes longer.
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = (ServerHttpRequest) exchange.getRequest();
String bodyString = getRequestBody(request);
DataBuffer bodyDataBuffer = stringBuffer(bodyString);
int len = bodyDataBuffer.readableByteCount();
URI requestUri = request.getURI();
URI ex = UriComponentsBuilder.fromUri(requestUri).build(true).toUri();
ServerHttpRequest newRequest = request.mutate().uri(ex).build();

    HttpHeaders myHeaders = new HttpHeaders();
    copyMultiValueMap(request.getHeaders(), myHeaders);
    myHeaders.remove(HttpHeaders.CONTENT_LENGTH);
    myHeaders.set(HttpHeaders.CONTENT_LENGTH, String.valueOf(len));

    Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);
    newRequest = new ServerHttpRequestDecorator(newRequest) {
        @Override
        public Flux<DataBuffer> getBody() { 
            return bodyFlux;
        }

        @Override
        public HttpHeaders getHeaders() {
            return myHeaders;               
        }
    };

    ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();

    return chain.filter(newExchange);


    //return chain.filter(exchange);
    //return returnMono(chain, exchange);
}

private static <K, V> void copyMultiValueMap(MultiValueMap<K,V> source, MultiValueMap<K,V> target) {
    source.forEach((key, value) -> target.put(key, new LinkedList<>(value)));
}

private DataBuffer stringBuffer(String value){
    byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
    NettyDataBufferFactory nettyDataBufferFactory = new 
    NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
    DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
    buffer.write(bytes);
    return buffer;
}



private String getRequestBody(ServerHttpRequest request) {
    Flux<DataBuffer> body = request.getBody();
    StringBuilder sb = new StringBuilder();        

    body.subscribe(buffer -> {
        byte[] bytes = new byte[buffer.readableByteCount()];
        buffer.read(bytes);
        DataBufferUtils.release(buffer);
        String bodyString = new String(bytes, StandardCharsets.UTF_8);
        sb.append(bodyString);
    });
    String str = sb.toString();
    if (str != null) {

        try {
            JSONObject obj = new JSONObject(str);
            obj.put("BSN_FLOWNUM", getBsnFlowNum("M1"));
            str = obj.toString();
        }catch(Exception e) {
            log.error(e.getMessage(), e);
        }           
    }        
    return str;
} 

private String getBsnFlowNum(String machineId) {
    Calendar ca = Calendar.getInstance();       
    this.flowNum = (this.flowNum + 1) % 100000;
    String str = String.format("%s%04d%02d%02d%02d%02d%02d%05d", 
            machineId, ca.get(Calendar.YEAR), ca.get(Calendar.MONTH) + 1,
            ca.get(Calendar.DAY_OF_MONTH), ca.get(Calendar.HOUR), ca.get(Calendar.MINUTE),
            ca.get(Calendar.SECOND), this.flowNum);
    return str;
}

Thank you very much for your excellent answer. I really appreciate it. This problem troubled me a lot the prior weekend.
-- An IT developer from Shanghai

really ?i just found this is used to modify request body not response body

i just found this is used to modify request body not response body.
i want to get response body, Is there anyone can help me?

I didn't get how to change the response body. I have a json in the body and I want to add a property to it.
Example config:

spring:
    cloud:
        gateway:
            routes:
              - id: test
                uri: http://jsonplaceholder.typicode.com:80
                predicates:
                  - Path=/**
                filters:
                  - MyFilter

My custom filter:

@Component
class MyFilter : GatewayFilterFactory {
    override fun apply(args: Tuple?): GatewayFilter {
        return GatewayFilter { exchange, chain ->
// I want to add a property to json response body, say, "a": 123. How?
            chain.filter(exchange)
        }
    }
}

I want to add a property to json response body, say, "a": 123. How?

You need to modify the header Content-Length, If you don't do this, the body may be truncated after you have modify the request body and the body becomes longer.
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = (ServerHttpRequest) exchange.getRequest();
String bodyString = getRequestBody(request);
DataBuffer bodyDataBuffer = stringBuffer(bodyString);
int len = bodyDataBuffer.readableByteCount();
URI requestUri = request.getURI();
URI ex = UriComponentsBuilder.fromUri(requestUri).build(true).toUri();
ServerHttpRequest newRequest = request.mutate().uri(ex).build();

    HttpHeaders myHeaders = new HttpHeaders();
    copyMultiValueMap(request.getHeaders(), myHeaders);
    myHeaders.remove(HttpHeaders.CONTENT_LENGTH);
    myHeaders.set(HttpHeaders.CONTENT_LENGTH, String.valueOf(len));

    Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);
    newRequest = new ServerHttpRequestDecorator(newRequest) {
        @Override
        public Flux<DataBuffer> getBody() {   
            return bodyFlux;
        }

        @Override
        public HttpHeaders getHeaders() {
          return myHeaders;               
        }
    };

    ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();

    return chain.filter(newExchange);


  //return chain.filter(exchange);
  //return returnMono(chain, exchange);
}

private static <K, V> void copyMultiValueMap(MultiValueMap<K,V> source, MultiValueMap<K,V> target) {
  source.forEach((key, value) -> target.put(key, new LinkedList<>(value)));
}

private DataBuffer stringBuffer(String value){
    byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
    NettyDataBufferFactory nettyDataBufferFactory = new 
    NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
    DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
    buffer.write(bytes);
    return buffer;
}



private String getRequestBody(ServerHttpRequest request) {
    Flux<DataBuffer> body = request.getBody();
    StringBuilder sb = new StringBuilder();        

    body.subscribe(buffer -> {
        byte[] bytes = new byte[buffer.readableByteCount()];
        buffer.read(bytes);
        DataBufferUtils.release(buffer);
        String bodyString = new String(bytes, StandardCharsets.UTF_8);
        sb.append(bodyString);
    });
    String str = sb.toString();
    if (str != null) {

      try {
          JSONObject obj = new JSONObject(str);
          obj.put("BSN_FLOWNUM", getBsnFlowNum("M1"));
          str = obj.toString();
      }catch(Exception e) {
          log.error(e.getMessage(), e);
      }           
    }        
    return str;
} 

private String getBsnFlowNum(String machineId) {
  Calendar ca = Calendar.getInstance();       
  this.flowNum = (this.flowNum + 1) % 100000;
  String str = String.format("%s%04d%02d%02d%02d%02d%02d%05d", 
          machineId, ca.get(Calendar.YEAR), ca.get(Calendar.MONTH) + 1,
          ca.get(Calendar.DAY_OF_MONTH), ca.get(Calendar.HOUR), ca.get(Calendar.MINUTE),
          ca.get(Calendar.SECOND), this.flowNum);
  return str;
}

Thank you very much for your excellent answer. I really appreciate it. This problem troubled me a lot the prior weekend.
-- An IT developer from Shanghai

really ?i just found this is used to modify request body not response body

yes,in my case i just need read request body ;
by the way ,if the request ls longger than 1024 should choose
springBootVersion = "2.1.1.RELEASE"
springCloudVersion = "2.1.0.BUILD-SNAPSHOT"

and

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    //@formatter:off
    return builder.routes()
                  .route("path_route", r -> r
                          .path("/**")
                          .filters(f -> f
                                  .addRequestHeader("ForceFowardUrl", "")
                                  .addRequestHeader("ReturnMessage", "")
                                  .modifyRequestBody(String.class, String.class,
                                                     (exchange, reqMessage) -> {

//do your business

return Mono.just(reqMessage);
})
) .uri("http://www.test.com/80"))

how to modify multipart/form-data request data?

how to modify multipart/form-data request data?

public class Application {

private static final Logger logger = LoggerFactory.getLogger(Application.class);

@Autowired
private ProcessControllerService processControllerService;

public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
}

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
                  .route("path_route", r -> r
                          .path("/efeppi/upfsms/*")
                          .filters(f -> f
                                  .addRequestHeader("TargetUrl", "")
                                  .addRequestHeader("GatewayDispatchErrorMessage", "")
                                  /*rebulid reoute and request*/
                                  .modifyRequestBody(String.class, String.class,
                                                     (exchange, reqMessage) -> {
                                                        //you can change request meessage and url here 

                                                         try {
                                                             reqMessage = processControllerService.doRequestDispatch(exchange,
                                                                                                                     reqMessage);

                                                         } catch (Exception ex) {
                                                             logger.error("some error happen withdeal ,formate General error message ", ex);

                                                             exchange.getAttributes()
                                                                     .put("GatewayDispatchErrorMessage", BaseCache.BR_OTHER_ERROR_MESSAGE);
                                                             reqMessage = BaseCache.BR_OTHER_ERROR_MESSAGE;

                                                         }
                                                         return Mono.just(reqMessage);
                                                     })
                          )
                          /*error route*/
                          .uri("http:test"))

                  .build();
}

@Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
    return http.httpBasic().and()
               .csrf().disable()
               .authorizeExchange()
               .pathMatchers("/anything/**").authenticated()
               .anyExchange().permitAll()
               .and()
               .build();
}

@Bean
public MapReactiveUserDetailsService reactiveUserDetailsService() {
    UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build();
    return new MapReactiveUserDetailsService(user);
}

@RequestMapping("/hystrixfallback")
public String hystrixfallback() {
    return "This is a fallback";
}

}

how to modify multipart/form-data request data?

public class Application {

private static final Logger logger = LoggerFactory.getLogger(Application.class);

@Autowired
private ProcessControllerService processControllerService;

public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
}

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
                  .route("path_route", r -> r
                          .path("/efeppi/upfsms/*")
                          .filters(f -> f
                                  .addRequestHeader("TargetUrl", "")
                                  .addRequestHeader("GatewayDispatchErrorMessage", "")
                                  /*rebulid reoute and request*/
                                  .modifyRequestBody(String.class, String.class,
                                                     (exchange, reqMessage) -> {
                                                      //you can change request meessage and url here 

                                                         try {
                                                             reqMessage = processControllerService.doRequestDispatch(exchange,
                                                                                                                     reqMessage);

                                                         } catch (Exception ex) {
                                                             logger.error("some error happen withdeal ,formate General error message ", ex);

                                                             exchange.getAttributes()
                                                                     .put("GatewayDispatchErrorMessage", BaseCache.BR_OTHER_ERROR_MESSAGE);
                                                             reqMessage = BaseCache.BR_OTHER_ERROR_MESSAGE;

                                                         }
                                                         return Mono.just(reqMessage);
                                                     })
                          )
                          /*error route*/
                          .uri("http:test"))

                  .build();
}

@Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
    return http.httpBasic().and()
               .csrf().disable()
               .authorizeExchange()
               .pathMatchers("/anything/**").authenticated()
               .anyExchange().permitAll()
               .and()
               .build();
}

@Bean
public MapReactiveUserDetailsService reactiveUserDetailsService() {
    UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build();
    return new MapReactiveUserDetailsService(user);
}

@RequestMapping("/hystrixfallback")
public String hystrixfallback() {
    return "This is a fallback";
}

}

This code is not applicable to multipart/form-data request.

how to modify multipart/form-data request data?

public class Application {

private static final Logger logger = LoggerFactory.getLogger(Application.class);

@Autowired
private ProcessControllerService processControllerService;

public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
}

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
                  .route("path_route", r -> r
                          .path("/efeppi/upfsms/*")
                          .filters(f -> f
                                  .addRequestHeader("TargetUrl", "")
                                  .addRequestHeader("GatewayDispatchErrorMessage", "")
                                  /*rebulid reoute and request*/
                                  .modifyRequestBody(String.class, String.class,
                                                     (exchange, reqMessage) -> {
                                                        //you can change request meessage and url here 

                                                         try {
                                                             reqMessage = processControllerService.doRequestDispatch(exchange,
                                                                                                                     reqMessage);

                                                         } catch (Exception ex) {
                                                             logger.error("some error happen withdeal ,formate General error message ", ex);

                                                             exchange.getAttributes()
                                                                     .put("GatewayDispatchErrorMessage", BaseCache.BR_OTHER_ERROR_MESSAGE);
                                                             reqMessage = BaseCache.BR_OTHER_ERROR_MESSAGE;

                                                         }
                                                         return Mono.just(reqMessage);
                                                     })
                          )
                          /*error route*/
                          .uri("http:test"))

                  .build();
}

@Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
    return http.httpBasic().and()
               .csrf().disable()
               .authorizeExchange()
               .pathMatchers("/anything/**").authenticated()
               .anyExchange().permitAll()
               .and()
               .build();
}

@Bean
public MapReactiveUserDetailsService reactiveUserDetailsService() {
    UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build();
    return new MapReactiveUserDetailsService(user);
}

@RequestMapping("/hystrixfallback")
public String hystrixfallback() {
    return "This is a fallback";
}

}

This code is not applicable to multipart/form-data request.

why?multipart/form-data request will be change to a encode String ,you can check the value of code in reqMessage you can split them with '=' and '&'

how to modify multipart/form-data request data?

public class Application {

private static final Logger logger = LoggerFactory.getLogger(Application.class);

@Autowired
private ProcessControllerService processControllerService;

public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
}

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
                  .route("path_route", r -> r
                          .path("/efeppi/upfsms/*")
                          .filters(f -> f
                                  .addRequestHeader("TargetUrl", "")
                                  .addRequestHeader("GatewayDispatchErrorMessage", "")
                                  /*rebulid reoute and request*/
                                  .modifyRequestBody(String.class, String.class,
                                                     (exchange, reqMessage) -> {
                                                      //you can change request meessage and url here 

                                                         try {
                                                             reqMessage = processControllerService.doRequestDispatch(exchange,
                                                                                                                     reqMessage);

                                                         } catch (Exception ex) {
                                                             logger.error("some error happen withdeal ,formate General error message ", ex);

                                                             exchange.getAttributes()
                                                                     .put("GatewayDispatchErrorMessage", BaseCache.BR_OTHER_ERROR_MESSAGE);
                                                             reqMessage = BaseCache.BR_OTHER_ERROR_MESSAGE;

                                                         }
                                                         return Mono.just(reqMessage);
                                                     })
                          )
                          /*error route*/
                          .uri("http:test"))

                  .build();
}

@Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
    return http.httpBasic().and()
               .csrf().disable()
               .authorizeExchange()
               .pathMatchers("/anything/**").authenticated()
               .anyExchange().permitAll()
               .and()
               .build();
}

@Bean
public MapReactiveUserDetailsService reactiveUserDetailsService() {
    UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build();
    return new MapReactiveUserDetailsService(user);
}

@RequestMapping("/hystrixfallback")
public String hystrixfallback() {
    return "This is a fallback";
}

}

This code is not applicable to multipart/form-data request.

why?multipart/form-data request will be change to a encode String ,you can check the value of code in reqMessage you can split them with '=' and '&'

I don't how to process file parameters...

how to modify multipart/form-data request data?

public class Application {

private static final Logger logger = LoggerFactory.getLogger(Application.class);

@Autowired
private ProcessControllerService processControllerService;

public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
}

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
                  .route("path_route", r -> r
                          .path("/efeppi/upfsms/*")
                          .filters(f -> f
                                  .addRequestHeader("TargetUrl", "")
                                  .addRequestHeader("GatewayDispatchErrorMessage", "")
                                  /*rebulid reoute and request*/
                                  .modifyRequestBody(String.class, String.class,
                                                     (exchange, reqMessage) -> {
                                                        //you can change request meessage and url here 

                                                         try {
                                                             reqMessage = processControllerService.doRequestDispatch(exchange,
                                                                                                                     reqMessage);

                                                         } catch (Exception ex) {
                                                             logger.error("some error happen withdeal ,formate General error message ", ex);

                                                             exchange.getAttributes()
                                                                     .put("GatewayDispatchErrorMessage", BaseCache.BR_OTHER_ERROR_MESSAGE);
                                                             reqMessage = BaseCache.BR_OTHER_ERROR_MESSAGE;

                                                         }
                                                         return Mono.just(reqMessage);
                                                     })
                          )
                          /*error route*/
                          .uri("http:test"))

                  .build();
}

@Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
    return http.httpBasic().and()
               .csrf().disable()
               .authorizeExchange()
               .pathMatchers("/anything/**").authenticated()
               .anyExchange().permitAll()
               .and()
               .build();
}

@Bean
public MapReactiveUserDetailsService reactiveUserDetailsService() {
    UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build();
    return new MapReactiveUserDetailsService(user);
}

@RequestMapping("/hystrixfallback")
public String hystrixfallback() {
    return "This is a fallback";
}

}

This code is not applicable to multipart/form-data request.

why?multipart/form-data request will be change to a encode String ,you can check the value of code in reqMessage you can split them with '=' and '&'

I don't how to process file parameters...
o sorry , i didn't try to rebulid file maybe it is a stream?

You can use the Foward config to receive the request in your RequestMapping URL, and pass down the request data by yourself 。

add the config like below to the application.yml:

  • id: trans_route
    uri: forward:///API
    predicates:
    - Path=/some path you want to modify the requestbody or response body/**

then you can get the request body and response body , just do what you want to do like modify the request body ,modify the response body

​@RequestMapping("/API")
public String API(@RequestBody(required = false)byte[] data, @RequestHeader Map head, ProxyExchange

    ........................
           //modify your request data, the request body
    rsp = restTemplate.postForEntity("http://" + yoururl, youdata, String.class);

            .................................
           //modify the response body
           return rsp;

}

@Bean
public RouteLocator routeConfig(RouteLocatorBuilder builder) {
return builder.routes()
.route("aaaa-route", r -> r.path("/aaaa/**")
.filters(f -> f.modifyRequestBody(String.class, String.class, MediaType.APPLICATION_JSON_VALUE,
(exchange, body) -> {
//body is the original body
String modifiedBody = xxService.modify(body);
return Mono.just(modifiedBody);

                        })
                        )
                .uri("lb://aaaa")
)
.build();

}

is the only method I found.

you could have a try.

but the YAML config about routes: default-filters & filters will be disabled. I do not know whether it is a defect.

how to modify multipart/form-data request data?

public class Application {

private static final Logger logger = LoggerFactory.getLogger(Application.class);

@Autowired
private ProcessControllerService processControllerService;

public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
}

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
                  .route("path_route", r -> r
                          .path("/efeppi/upfsms/*")
                          .filters(f -> f
                                  .addRequestHeader("TargetUrl", "")
                                  .addRequestHeader("GatewayDispatchErrorMessage", "")
                                  /*rebulid reoute and request*/
                                  .modifyRequestBody(String.class, String.class,
                                                     (exchange, reqMessage) -> {
                                                      //you can change request meessage and url here 

                                                         try {
                                                             reqMessage = processControllerService.doRequestDispatch(exchange,
                                                                                                                     reqMessage);

                                                         } catch (Exception ex) {
                                                             logger.error("some error happen withdeal ,formate General error message ", ex);

                                                             exchange.getAttributes()
                                                                     .put("GatewayDispatchErrorMessage", BaseCache.BR_OTHER_ERROR_MESSAGE);
                                                             reqMessage = BaseCache.BR_OTHER_ERROR_MESSAGE;

                                                         }
                                                         return Mono.just(reqMessage);
                                                     })
                          )
                          /*error route*/
                          .uri("http:test"))

                  .build();
}

@Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
    return http.httpBasic().and()
               .csrf().disable()
               .authorizeExchange()
               .pathMatchers("/anything/**").authenticated()
               .anyExchange().permitAll()
               .and()
               .build();
}

@Bean
public MapReactiveUserDetailsService reactiveUserDetailsService() {
    UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build();
    return new MapReactiveUserDetailsService(user);
}

@RequestMapping("/hystrixfallback")
public String hystrixfallback() {
    return "This is a fallback";
}

}

This code is not applicable to multipart/form-data request.

why?multipart/form-data request will be change to a encode String ,you can check the value of code in reqMessage you can split them with '=' and '&'

I don't how to process file parameters...
o sorry , i didn't try to rebulid file maybe it is a stream?

While that (as your sample), the YAML default-filters and each route-filters will be disabled.
Did you seen this situation before ? And how to process this issue ?
Could you provide me some sugguest, thanks.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tony-clarke-amdocs picture tony-clarke-amdocs  ·  32Comments

zjengjie picture zjengjie  ·  27Comments

laudylcp picture laudylcp  ·  20Comments

vpavlyuk picture vpavlyuk  ·  37Comments

renanpalmeira picture renanpalmeira  ·  30Comments