spring-cloud / spring-cloud-gateway

An API Gateway built on Spring Framework and Spring Boot providing routing and more.
http://cloud.spring.io
Apache License 2.0
4.52k stars 3.32k forks source link

Spring Cloud 2023.0.1: unable to read CACHED_REQUEST_BODY_ATTR from the ServerWebExchange #3566

Open dtsukinovsky opened 4 hours ago

dtsukinovsky commented 4 hours ago

Describe the bug After migration of Spring Cloud from 2023.0.0 to 2023.0.3 we experienced the issue of inability to get CACHED_REQUEST_BODY_ATTR in one of the GlobalFilters:

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
...
String bodyString = exchange.getAttribute(ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR);
...
}

After execution of the filter above we're getting null for bodyString, while in Spring Cloud 2023.0.0 we were getting the request payload as a string. We do NOT call this line multiple times or in any kind of loop.

I also posted this in the closed PR which might be related: https://github.com/spring-cloud/spring-cloud-gateway/pull/2971#issuecomment-2432695585

Any advise will be appreciated.

Sorry for the late reaction, we do Spring Cloud upgrades not too often.

spencergibb commented 3 hours ago

Can you provide your gateway configuration and exact steps to reproduce the problem?

dtsukinovsky commented 2 hours ago

Gateway configuration:

spring:
  application:
    name: api-gateway
  profiles:
    active: '@spring.profiles.active@'
  output:
    ansi:
      enabled: ALWAYS
  webflux:
    static-path-pattern: "/**"
  cloud:
    gateway:
      default-filters:
      - AddResponseHeader=Strict-Transport-Security, max-age=31536000;includeSubDomains;preload
      routes:
      - id: service1
        uri: https://service1
        predicates:
        - Path=/service1/**
        filters:
        - name: CacheRequestBody
          args:
            bodyClass: java.lang.String
      - id: service2
        uri: https://service2
        predicates:
        - Path=/service2/**
      - id: service3
        uri: https://service3
        predicates:
        - Path=/service3/**
        filters:
        - name: CacheRequestBody
          args:
            bodyClass: java.lang.String
      httpclient:
        connect-timeout: 600000
        response-timeout: 600s
    gcp:
      logging:
        enabled: true

Steps to reproduce: nothing fancy here, as you can see from the config. Both service1 & service3 add the CacheRequestBody predefined filter to cache the request payload. After that we have a custom GlobalFilter in our gateway service trying to read the cached content:

@Order(1)
@Component
public class CustomFilter implements GlobalFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String bodyString = exchange.getAttribute(ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR);
        JsonObject bodyJson = new Gson().fromJson(bodyString, JsonObject.class);
        LOGGER.info(bodyJson.get("attr_name").getAsString());
    }
}
dtsukinovsky commented 2 hours ago

Reading 2023.0.1 release notes more carefully I see that support for ordering of global filters was added in this release - but we had the filters annotated with @Order way before that and I thought the ordering is working already... May be this is the root cause of our current issue @spencergibb ?

https://github.com/spring-cloud/spring-cloud-gateway/pull/2805