Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] NoSuchMethodError: 'org.springframework.web.reactive.function.server.ServerResponse$BodyBuilder #3298

Open
JavaLionLi opened this issue Dec 29, 2023 · 9 comments · May be fixed by #3379
Labels
area/integrations Issues or PRs related to integrations with open-source components

Comments

@JavaLionLi
Copy link

Issue Description

Type: bug report

Describe what happened

Describe what you expected to happen

How to reproduce it (as minimally and precisely as possible)

image
image
image

触发限流后 报异常 NoSuchMethodError 感觉是依赖版本适配问题 senintel的gateway插件对新版本gateway适配有问题

2023-12-29 17:42:05 [reactor-http-nio-16] WARN  reactor.core.Exceptions
 - throwIfFatal detected a jvm fatal exception, which is thrown and logged below:
java.lang.NoSuchMethodError: 'org.springframework.web.reactive.function.server.ServerResponse$BodyBuilder org.springframework.web.reactive.function.server.ServerResponse.status(org.springframework.http.HttpStatus)'
	at com.alibaba.csp.sentinel.adapter.gateway.sc.callback.DefaultBlockRequestHandler.handleRequest(DefaultBlockRequestHandler.java:45)
	at org.dromara.gateway.handler.SentinelFallbackHandler.handleBlockedRequest(SentinelFallbackHandler.java:34)
	at org.dromara.gateway.handler.SentinelFallbackHandler.handle(SentinelFallbackHandler.java:30)
	at org.springframework.web.server.handler.ExceptionHandlingWebHandler.lambda$handle$0(ExceptionHandlingWebHandler.java:77)
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94)
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:106)
	at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onError(FluxOnAssembly.java:544)
	at reactor.core.publisher.Operators.error(Operators.java:198)
	at reactor.core.publisher.MonoError.subscribe(MonoError.java:53)
	at reactor.core.publisher.Mono.subscribe(Mono.java:4495)
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103)
	at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onError(FluxOnAssembly.java:544)
	at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onError(FluxOnAssembly.java:544)
	at reactor.core.publisher.FluxTap$TapSubscriber.onError(FluxTap.java:254)
	at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onError(FluxOnAssembly.java:544)
	at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onError(FluxOnAssembly.java:544)
	at reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.onError(FluxDoFinally.java:119)
	at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onError(FluxContextWrite.java:121)
	at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onError(FluxOnAssembly.java:544)
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondError(MonoFlatMap.java:241)
	at reactor.core.publisher.MonoFlatMap$FlatMapInner.onError(MonoFlatMap.java:315)
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onError(MonoFlatMap.java:180)
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onError(MonoIgnoreThen.java:278)
	at reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.onError(FluxDoFinally.java:119)
	at com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorSubscriber.entryWhenSubscribed(SentinelReactorSubscriber.java:102)
	at com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorSubscriber.doWithContextOrCurrent(SentinelReactorSubscriber.java:78)
	at com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorSubscriber.hookOnSubscribe(SentinelReactorSubscriber.java:112)
	at com.alibaba.csp.sentinel.adapter.reactor.InheritableBaseSubscriber.onSubscribe(InheritableBaseSubscriber.java:136)
	at com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorSubscriber.onSubscribe(SentinelReactorSubscriber.java:37)
	at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onSubscribe(MonoPeekTerminal.java:152)
	at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onSubscribe(FluxPeekFuseable.java:816)
	at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:50)
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
	at com.alibaba.csp.sentinel.adapter.reactor.MonoSentinelOperator.subscribe(MonoSentinelOperator.java:40)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
	at reactor.core.publisher.Mono.subscribe(Mono.java:4495)
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:263)
	at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51)
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165)
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
	at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:74)
	at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82)
	at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.innerNext(FluxConcatMapNoPrefetch.java:258)
	at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:863)
	at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122)
	at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:74)
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:158)
	at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:122)
	at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82)
	at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.innerNext(FluxConcatMapNoPrefetch.java:258)
	at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:863)
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
	at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:180)
	at reactor.core.publisher.MonoFilterWhen$MonoFilterWhenMain.onNext(MonoFilterWhen.java:136)
	at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545)
	at reactor.core.publisher.MonoFilterWhen$MonoFilterWhenMain.request(MonoFilterWhen.java:182)
	at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.request(MonoPeekTerminal.java:139)
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2341)
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onSubscribe(FluxOnErrorResume.java:74)
	at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onSubscribe(MonoPeekTerminal.java:152)
	at reactor.core.publisher.MonoFilterWhen$MonoFilterWhenMain.onSubscribe(MonoFilterWhen.java:100)
	at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55)
	at reactor.core.publisher.Mono.subscribe(Mono.java:4495)
	at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.onNext(FluxConcatMapNoPrefetch.java:206)
	at reactor.core.publisher.FluxDematerialize$DematerializeSubscriber.onNext(FluxDematerialize.java:98)
	at reactor.core.publisher.FluxDematerialize$DematerializeSubscriber.onNext(FluxDematerialize.java:44)
	at reactor.core.publisher.FluxIterable$IterableSubscription.slowPath(FluxIterable.java:335)
	at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:294)
	at reactor.core.publisher.FluxDematerialize$DematerializeSubscriber.request(FluxDematerialize.java:127)
	at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.innerComplete(FluxConcatMapNoPrefetch.java:274)
	at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onComplete(FluxConcatMap.java:887)
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2205)
	at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onComplete(MonoPeekTerminal.java:299)
	at reactor.core.publisher.MonoFilterWhen$MonoFilterWhenMain.onNext(MonoFilterWhen.java:141)
	at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2545)
	at reactor.core.publisher.MonoFilterWhen$MonoFilterWhenMain.request(MonoFilterWhen.java:182)
	at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.request(MonoPeekTerminal.java:139)
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.request(Operators.java:2305)
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.request(Operators.java:2305)
	at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.request(FluxConcatMapNoPrefetch.java:338)
	at reactor.core.publisher.MonoNext$NextSubscriber.request(MonoNext.java:108)
	at reactor.core.publisher.FluxMap$MapSubscriber.request(FluxMap.java:164)
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.request(Operators.java:2305)
	at reactor.core.publisher.FluxMap$MapSubscriber.request(FluxMap.java:164)
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.request(Operators.java:2305)
	at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.request(FluxConcatMapNoPrefetch.java:338)
	at reactor.core.publisher.MonoNext$NextSubscriber.request(MonoNext.java:108)
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2341)
	at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2215)
	at reactor.core.publisher.MonoNext$NextSubscriber.onSubscribe(MonoNext.java:70)
	at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.onSubscribe(FluxConcatMapNoPrefetch.java:164)
	at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:201)
	at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:83)
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
	at reactor.core.publisher.Mono.subscribe(Mono.java:4495)
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:263)
	at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51)
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
	at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55)
	at reactor.netty.http.server.HttpServer$HttpServerHandle.onStateChange(HttpServer.java:1169)
	at reactor.netty.ReactorNetty$CompositeConnectionObserver.onStateChange(ReactorNetty.java:710)
	at reactor.netty.transport.ServerTransport$ChildObserver.onStateChange(ServerTransport.java:481)
	at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:652)
	at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:114)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:238)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318)
	at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:833)

Tell us your environment

Anything else we need to know?

@sczyh30 sczyh30 added the area/integrations Issues or PRs related to integrations with open-source components label Jan 2, 2024
@Random-pro
Copy link

同问,在JDK17+spring-cloud-starter-alibaba-sentinel 2022.0.0.0-RC2下,当触发限流时会导致com.alibaba.csp.sentinel.adapter.spring.webflux.callback.DefaultBlockRequestHandler#htmlErrorResponse报错java.lang.NoSuchMethodError: 'org.springframework.web.reactive.function.server.ServerResponse$BodyBuilder org.springframework.web.reactive.function.server.ServerResponse.status(org.springframework.http.HttpStatus)'

@zhuomuniao1986
Copy link

遇到相同问题
项目环境是JDK17,依赖的spring-cloud-alibaba-sentinel-gateway版本为2022.0.0.0
检查发现其下的sentinel-spring-cloud-gateway-adapter-1.8.6.jar是JDK8编译的,如果下载源码用JDK17重新编译打包替换项目中依赖的sentinel-spring-cloud-gateway-adapter-1.8.6.jar可以解决此问题。

或者也可以通过自定义逻辑处理被限流的请求(不使用默认的DefaultBlockRequestHandler)来解决此问题

@Configuration
public class SentinelConfig {
    public SentinelConfig() {
        GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable ex) {
                return ServerResponse.ok().body(Mono.just("限流啦,请求太频繁"), String.class);
            }
        });
    }
}

@JavaLionLi
Copy link
Author

image
将DefaultBlockRequestHandler源码copy出来同包名覆盖 可以临时解决这个问题 后续等官方修复吧

@cxhello
Copy link

cxhello commented Apr 19, 2024

@zhuomuniao1986 请教下为什么使用JDK17重新编译就可以,是因为 Spring 限制么?

@zhuomuniao1986
Copy link

@zhuomuniao1986 请教下为什么使用JDK17重新编译就可以,是因为 Spring 限制么?

今天再次试了一下,发现直接用JDK17重新编译sentinel-spring-cloud-gateway-adapter-1.8.6是不行的,估计是因为DefaultBlockRequestHandler中使用到的ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)在不同版本中参数类型不一样导致的,在spring-webflux:6.0.4中ServerResponse.status(HttpStatusCode status)方法需要的是HttpStatusCode,而这里传入的是HttpStatus,所以在spring-webflux:6.0.4中ServerResponse没有找到对应的方法。

@cxhello
Copy link

cxhello commented Apr 19, 2024

@zhuomuniao1986 但HttpStatus实现了HttpStatusCode接口。

@zhuomuniao1986
Copy link

@zhuomuniao1986 但HttpStatus实现了HttpStatusCode接口。

是的,但是可能是因为DefaultBlockRequestHandler中使用到的ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)中的HttpStatus还是老的(未实现接口)

下面是我对这个问题的简单复现

新建项目A,模拟spring中的ServerResponse和HttpStatus

public interface ServerResponse {

    static void status(HttpStatus status) {
        System.out.println("==>" + status);
    }

}
public enum HttpStatus {

    TOO_MANY_REQUESTS;

}

新建项目B,模拟alibaba中的DefaultBlockRequestHandler,在handleRequest方法中调用项目A的ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS);

public class DefaultBlockRequestHandler {

    public void handleRequest() {
        ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS);
    }

}

新建项目C,调用项目B中的方法进行测试

public class Test {

    public static void main(String[] args) {
        DefaultBlockRequestHandler dv = new DefaultBlockRequestHandler();
        dv.handleRequest();
    }

}

这时测试输出正常。

接下来,修改项目A,升级一个新的版本:

新建接口

public interface HttpStatusCode {

    void xx();

}

修改枚举类,实现上面的接口

public enum HttpStatus implements HttpStatusCode{

    TOO_MANY_REQUESTS;

    @Override
    public void xx() {
        System.out.println("zZZZZZZ");
    }
}

修改ServerResponse status的入参为HttpStatusCode接口

public interface ServerResponse {

    static void status(HttpStatusCode status) {
        System.out.println("==>" + status);
    }

}

然后在项目C中引用项目A的新版本,这时再运行就报错NoSuchMethodError

注:以上所有项目都在jdk17下进行。

@cxhello
Copy link

cxhello commented Apr 19, 2024

@zhuomuniao1986 恩,现在的问题应该就是Sentinel需要依赖 Spring6 然后重新编译一下就可以了。

@zhuomuniao1986
Copy link

@zhuomuniao1986 恩,现在的问题应该就是Sentinel需要依赖 Spring6 然后重新编译一下就可以了。

是的。

拿上面的简单复现进行分析,发现
项目B模拟的DefaultBlockRequestHandler通过javap查看class文件,结果下图右边所示;
如果项目B依赖项目A的新版本,然后再查看,结果如下图左边所示(项目B本身代码没有修改,但是class文件却和之前不一样)。

image

可以看出,右边去调用ServerResponse.status的参数类型为HttpStatus方法,这个在项目A的新版本中是不存在的,所以报NoSuchMethodError错误;而左边是调用ServerResponse.status的参数类型为HttpStatusCode的方法,这个在项目A的新版本中是存在的,所以不报错了。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/integrations Issues or PRs related to integrations with open-source components
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants