spring-cloud-gateway icon indicating copy to clipboard operation
spring-cloud-gateway copied to clipboard

Spring Cloud Gateway Server MVC rateLimit filter(Bucket4jFilter) will got UnsupportedOperationException when response headers is ReadOnlyHttpHeaders

Open zzphyh opened this issue 1 year ago • 2 comments

Describe the bug I use rateLimit(Bucket4jFilter) filter with a handler, the handler will return response as below.

return ServerResponse.ok().body(result);

For that response, the serverResponse.headers() will return a ReadOnlyHttpHeaders. But the Bucket4jFilter will try to add a header into the serverResponse.headers(), that will cause java.lang.UnsupportedOperationException.

			if (allowed) {
				ServerResponse serverResponse = next.handle(request);
				serverResponse.headers().add(config.getHeaderName(), String.valueOf(remainingTokens));
				return serverResponse;
			}

I use Spring Cloud Gateway Server MVC version 4.1.2 <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway-mvc</artifactId> 4.1.2

zzphyh avatar Apr 10 '24 02:04 zzphyh

I don't understand your full configuration. Can you provide it. Where does return ServerResponse.ok().body(result); live?

spencergibb avatar Apr 10 '24 23:04 spencergibb

I don't understand your full configuration. Can you provide it. Where does return ServerResponse.ok().body(result); live?

I have added a custom handler, the code in spring.factories is:

org.springframework.cloud.gateway.server.mvc.handler.HandlerSupplier=\
test.HandlerFunctions.MyHandlerSupplier

Custom handler code:

public abstract class HandlerFunctions {

    public static HandlerFunction<ServerResponse> dubbo() {
        return new DubboHandler();
    }

    public static class MyHandlerSupplier implements HandlerSupplier {

        @Override
        public Collection<Method> get() {
            return Arrays.asList(HandlerFunctions.class.getMethods());
        }
    }
}
public class DubboHandler implements HandlerFunction<ServerResponse> {
    @Override
    public ServerResponse handle(@Nonnull ServerRequest request) {
        try {
            final JSONObject result = callDubboRPC(request);
            return ServerResponse.ok().body(result);
        } catch (Exception e) {
            log.error("forward to rpc failed.", e);
            return ServerResponse.status(BAD_GATEWAY).body(new Result<>(HTTP_FORWARD_DUBBO_ERROR));
        }
    }
}

The routing configuration is similar to the following (excluding the rate-limiting part):

spring:
  cloud:
    gateway:
      mvc:
        routes:
          - id: im_route1
            uri: dubbo://dubboserviceaddress
            predicates:
              - Path=/calltodubbo
              - Method=POST

zzphyh avatar Apr 17 '24 06:04 zzphyh