我尝试使用@Client界面检索度量。当我使用自己的松散类型类时:
data class Tags(
val tag: String,
val values: List<String>
)
data class Metrics(
val names: List<String>?,
val name: String?,
val measurements: List<Map<String, Any>>?,
val availableTags: List<Tags>?
)
和界面:
@Client("/metrics")
interface MetricsClient {
@Get("{/name}")
fun metrics(name: String? = null): Metrics
}
我得到了期望的数据,但是我尝试使用端点中定义的类使代码与服务器客户端报告“空主体”响应保持同步。
带有的代码不起作用:
@Client("/metrics")
interface MetricsClient {
@Get("/")
fun metricsList(): MetricsEndpoint.MetricNames
@Get("/{name}")
fun metricsDetails(name: String): MetricsEndpoint.MetricDetails
}
对client.metricsList()
的首次调用会引发异常,表明正文为空。
此代码有什么问题?为什么不起作用?
编辑: 我为所有功能启用了DEBUG,这就是通过使用以下URL重新加载页面所得到的:
23:22:27.683 [pool-1-thread-7] DEBUG i.m.context.DefaultBeanContext - Resolved existing bean [io.micronaut.health.HeartbeatTask@55d58825] for type [class io.micronaut.health.HeartbeatTask] and qualifier [null]
23:22:27.683 [pool-1-thread-7] DEBUG i.m.c.e.ApplicationEventPublisher - Publishing event: io.micronaut.health.HeartbeatEvent[source=io.micronaut.http.server.netty.NettyEmbeddedServerInstance@2d64160c]
23:22:27.683 [pool-1-thread-7] DEBUG i.m.context.DefaultBeanContext - Resolving beans for type: <HeartbeatEvent> io.micronaut.context.event.ApplicationEventListener
23:22:29.469 [nioEventLoopGroup-1-14] DEBUG i.m.h.server.netty.NettyHttpServer - Server localhost:8080 Received Request: GET /khal
23:22:29.469 [nioEventLoopGroup-1-14] DEBUG i.m.h.s.netty.RoutingInBoundHandler - Matching route GET - /khal
23:22:29.469 [nioEventLoopGroup-1-14] DEBUG i.m.h.s.netty.RoutingInBoundHandler - Matched route GET - /khal to controller class com.helpchoice.kotlin.mn.management.$EndpointsControllerDefinition$Intercepted
23:22:29.473 [nioEventLoopGroup-1-16] DEBUG i.m.http.client.DefaultHttpClient - Sending HTTP Request: GET /metrics
23:22:29.474 [nioEventLoopGroup-1-16] DEBUG i.m.http.client.DefaultHttpClient - Chosen Server: localhost(8080)
23:22:29.476 [nioEventLoopGroup-1-17] DEBUG i.m.h.server.netty.NettyHttpServer - Server localhost:8080 Received Request: GET /metrics
23:22:29.476 [nioEventLoopGroup-1-17] DEBUG i.m.h.s.netty.RoutingInBoundHandler - Matching route GET - /metrics
23:22:29.476 [nioEventLoopGroup-1-17] DEBUG i.m.h.s.netty.RoutingInBoundHandler - Matched route GET - /metrics to controller class io.micronaut.configuration.metrics.management.endpoint.MetricsEndpoint
23:22:29.479 [pool-1-thread-6] DEBUG i.m.h.s.netty.RoutingInBoundHandler - Encoding emitted response object [io.micronaut.configuration.metrics.management.endpoint.MetricsEndpoint$MetricNames@719dde52] using codec: io.micronaut.jackson.codec.JsonMediaTypeCodec@6c9320c2
23:22:29.482 [nioEventLoopGroup-1-16] DEBUG i.m.http.client.DefaultHttpClient - Unable to decode response body using codec JsonMediaTypeCodec:Error decoding JSON stream for type [class io.micronaut.configuration.metrics.management.endpoint.MetricsEndpoint$MetricNames]: Cannot construct instance of `io.micronaut.configuration.metrics.management.endpoint.MetricsEndpoint$MetricNames` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (byte[])"{"names":["executor","executor.active","executor.completed","executor.pool.size","executor.queued","http.client.requests","http.server.requests","jvm.buffer.count","jvm.buffer.memory.used","jvm.buffer.total.capacity","jvm.classes.loaded","jvm.classes.unloaded","jvm.gc.live.data.size","jvm.gc.max.data.size","jvm.gc.memory.allocated","jvm.gc.memory.promoted","jvm.gc.pause","jvm.memory.committed","jvm.memory.max","jvm.memory.used","jvm.threads.daemon","jvm.threads.live","jvm.threads.peak","logback."[truncated 171 bytes]; line: 1, column: 2]
io.micronaut.http.codec.CodecException: Error decoding JSON stream for type [class io.micronaut.configuration.metrics.management.endpoint.MetricsEndpoint$MetricNames]: Cannot construct instance of `io.micronaut.configuration.metrics.management.endpoint.MetricsEndpoint$MetricNames` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (byte[])"{"names":["executor","executor.active","executor.completed","executor.pool.size","executor.queued","http.client.requests","http.server.requests","jvm.buffer.count","jvm.buffer.memory.used","jvm.buffer.total.capacity","jvm.classes.loaded","jvm.classes.unloaded","jvm.gc.live.data.size","jvm.gc.max.data.size","jvm.gc.memory.allocated","jvm.gc.memory.promoted","jvm.gc.pause","jvm.memory.committed","jvm.memory.max","jvm.memory.used","jvm.threads.daemon","jvm.threads.live","jvm.threads.peak","logback."[truncated 171 bytes]; line: 1, column: 2]
at io.micronaut.jackson.codec.JsonMediaTypeCodec.decode(JsonMediaTypeCodec.java:139)
at io.micronaut.http.client.FullNettyClientHttpResponse.convertByteBuf(FullNettyClientHttpResponse.java:239)
at io.micronaut.http.client.FullNettyClientHttpResponse.lambda$getBody$1(FullNettyClientHttpResponse.java:189)
at java.util.HashMap.computeIfAbsent(HashMap.java:1126)
at io.micronaut.http.client.FullNettyClientHttpResponse.getBody(FullNettyClientHttpResponse.java:167)
at io.micronaut.http.client.FullNettyClientHttpResponse.<init>(FullNettyClientHttpResponse.java:100)
at io.micronaut.http.client.DefaultHttpClient$10.channelRead0(DefaultHttpClient.java:1743)
at io.micronaut.http.client.DefaultHttpClient$10.channelRead0(DefaultHttpClient.java:1705)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.micronaut.http.netty.stream.HttpStreamsHandler.channelRead(HttpStreamsHandler.java:186)
at io.micronaut.http.netty.stream.HttpStreamsClientHandler.channelRead(HttpStreamsClientHandler.java:181)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:297)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:644)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:579)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:496)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:458)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:53)
at io.micronaut.http.context.ServerRequestContext.lambda$instrument$0(ServerRequestContext.java:69)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:745)
23:22:29.483 [pool-1-thread-5] ERROR i.m.r.intercept.RecoveryInterceptor - Type [com.helpchoice.kotlin.mn.management.MetricsClient$Intercepted] executed with error: Empty body
io.micronaut.http.client.exceptions.HttpClientResponseException: Empty body
at io.micronaut.http.client.BlockingHttpClient.lambda$retrieve$0(BlockingHttpClient.java:141)
at java.util.Optional.orElseThrow(Optional.java:290)
at io.micronaut.http.client.BlockingHttpClient.retrieve(BlockingHttpClient.java:141)
at io.micronaut.http.client.interceptor.HttpClientIntroductionAdvice.intercept(HttpClientIntroductionAdvice.java:501)
at io.micronaut.aop.MethodInterceptor.intercept(MethodInterceptor.java:41)
at io.micronaut.aop.chain.InterceptorChain.proceed(InterceptorChain.java:147)
at io.micronaut.retry.intercept.RecoveryInterceptor.intercept(RecoveryInterceptor.java:74)
at io.micronaut.aop.MethodInterceptor.intercept(MethodInterceptor.java:41)
at io.micronaut.aop.chain.InterceptorChain.proceed(InterceptorChain.java:147)
at com.helpchoice.kotlin.mn.management.MetricsClient$Intercepted.metricsList(Unknown Source)
at com.helpchoice.kotlin.mn.management.EndpointsController.metrics(EndpointsController.kt:142)
at com.helpchoice.kotlin.mn.management.$EndpointsControllerDefinition$$exec4.invokeInternal(Unknown Source)
at io.micronaut.context.AbstractExecutableMethod.invoke(AbstractExecutableMethod.java:145)
at io.micronaut.context.DefaultBeanContext$BeanExecutionHandle.invoke(DefaultBeanContext.java:2447)
at io.micronaut.web.router.AbstractRouteMatch.execute(AbstractRouteMatch.java:237)
at io.micronaut.web.router.RouteMatch.execute(RouteMatch.java:123)
at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$buildResultEmitter$16(RoutingInBoundHandler.java:1288)
at io.reactivex.internal.operators.flowable.FlowableCreate.subscribeActual(FlowableCreate.java:71)
at io.reactivex.Flowable.subscribe(Flowable.java:14479)
at io.reactivex.internal.operators.flowable.FlowableMap.subscribeActual(FlowableMap.java:37)
at io.reactivex.Flowable.subscribe(Flowable.java:14479)
at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
at io.reactivex.Flowable.subscribe(Flowable.java:14479)
at io.reactivex.Flowable.subscribe(Flowable.java:14429)
at io.micronaut.http.context.ServerRequestTracingPublisher.lambda$subscribe$0(ServerRequestTracingPublisher.java:53)
at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:53)
at io.micronaut.http.context.ServerRequestTracingPublisher.subscribe(ServerRequestTracingPublisher.java:53)
at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29)
at io.reactivex.Flowable.subscribe(Flowable.java:14479)
at io.reactivex.internal.operators.flowable.FlowableSwitchMap.subscribeActual(FlowableSwitchMap.java:49)
at io.reactivex.Flowable.subscribe(Flowable.java:14479)
at io.reactivex.Flowable.subscribe(Flowable.java:14429)
at io.micronaut.configuration.metrics.binder.web.WebMetricsPublisher.subscribe(WebMetricsPublisher.java:123)
at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29)
at io.reactivex.Flowable.subscribe(Flowable.java:14479)
at io.reactivex.Flowable.subscribe(Flowable.java:14426)
at io.reactivex.internal.operators.flowable.FlowableSubscribeOn$SubscribeOnSubscriber.run(FlowableSubscribeOn.java:82)
at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker$BooleanRunnable.run(ExecutorScheduler.java:260)
at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker.run(ExecutorScheduler.java:225)
at io.micrometer.core.instrument.composite.CompositeTimer.record(CompositeTimer.java:79)
at io.micrometer.core.instrument.Timer.lambda$wrap$0(Timer.java:126)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
23:22:29.484 [pool-1-thread-5] ERROR i.m.h.s.netty.RoutingInBoundHandler - Unexpected error occurred: Empty body
io.micronaut.http.client.exceptions.HttpClientResponseException: Empty body
at io.micronaut.http.client.BlockingHttpClient.lambda$retrieve$0(BlockingHttpClient.java:141)
at java.util.Optional.orElseThrow(Optional.java:290)
at io.micronaut.http.client.BlockingHttpClient.retrieve(BlockingHttpClient.java:141)
at io.micronaut.http.client.interceptor.HttpClientIntroductionAdvice.intercept(HttpClientIntroductionAdvice.java:501)
at io.micronaut.aop.MethodInterceptor.intercept(MethodInterceptor.java:41)
at io.micronaut.aop.chain.InterceptorChain.proceed(InterceptorChain.java:147)
at io.micronaut.retry.intercept.RecoveryInterceptor.intercept(RecoveryInterceptor.java:74)
at io.micronaut.aop.MethodInterceptor.intercept(MethodInterceptor.java:41)
at io.micronaut.aop.chain.InterceptorChain.proceed(InterceptorChain.java:147)
at com.helpchoice.kotlin.mn.management.MetricsClient$Intercepted.metricsList(Unknown Source)
at com.helpchoice.kotlin.mn.management.EndpointsController.metrics(EndpointsController.kt:142)
at com.helpchoice.kotlin.mn.management.$EndpointsControllerDefinition$$exec4.invokeInternal(Unknown Source)
at io.micronaut.context.AbstractExecutableMethod.invoke(AbstractExecutableMethod.java:145)
at io.micronaut.context.DefaultBeanContext$BeanExecutionHandle.invoke(DefaultBeanContext.java:2447)
at io.micronaut.web.router.AbstractRouteMatch.execute(AbstractRouteMatch.java:237)
at io.micronaut.web.router.RouteMatch.execute(RouteMatch.java:123)
at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$buildResultEmitter$16(RoutingInBoundHandler.java:1288)
at io.reactivex.internal.operators.flowable.FlowableCreate.subscribeActual(FlowableCreate.java:71)
at io.reactivex.Flowable.subscribe(Flowable.java:14479)
at io.reactivex.internal.operators.flowable.FlowableMap.subscribeActual(FlowableMap.java:37)
at io.reactivex.Flowable.subscribe(Flowable.java:14479)
at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
at io.reactivex.Flowable.subscribe(Flowable.java:14479)
at io.reactivex.Flowable.subscribe(Flowable.java:14429)
at io.micronaut.http.context.ServerRequestTracingPublisher.lambda$subscribe$0(ServerRequestTracingPublisher.java:53)
at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:53)
at io.micronaut.http.context.ServerRequestTracingPublisher.subscribe(ServerRequestTracingPublisher.java:53)
at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29)
at io.reactivex.Flowable.subscribe(Flowable.java:14479)
at io.reactivex.internal.operators.flowable.FlowableSwitchMap.subscribeActual(FlowableSwitchMap.java:49)
at io.reactivex.Flowable.subscribe(Flowable.java:14479)
at io.reactivex.Flowable.subscribe(Flowable.java:14429)
at io.micronaut.configuration.metrics.binder.web.WebMetricsPublisher.subscribe(WebMetricsPublisher.java:123)
at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29)
at io.reactivex.Flowable.subscribe(Flowable.java:14479)
at io.reactivex.Flowable.subscribe(Flowable.java:14426)
at io.reactivex.internal.operators.flowable.FlowableSubscribeOn$SubscribeOnSubscriber.run(FlowableSubscribeOn.java:82)
at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker$BooleanRunnable.run(ExecutorScheduler.java:260)
at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker.run(ExecutorScheduler.java:225)
at io.micrometer.core.instrument.composite.CompositeTimer.record(CompositeTimer.java:79)
at io.micrometer.core.instrument.Timer.lambda$wrap$0(Timer.java:126)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
23:22:29.484 [pool-1-thread-5] DEBUG i.m.h.s.netty.RoutingInBoundHandler - Encoding emitted response object [Internal Server Error: Empty body] using codec: io.micronaut.jackson.codec.JsonMediaTypeCodec@6c9320c2
答案 0 :(得分:0)
我解决这个问题的方法是明确地将类型声明为 Argument
client.toBlocking()
.exchange(request, Argument.of(Payload::class.java, DataDto::class.java))
其中我的端点的返回类型是 Payload<DataDto>
做的时候:
client.toBlocking()
.exchange<RequestDto, Payload<DataDto>>(request)
主体类型似乎在 exchange
方法的深处丢失了。