Отправка обратно HttpResponse.notFound() приводит к исключению HttpClientResponseException
У меня есть простой контроллер:
@Validated
@Controller(value = "/api/issues")
class IssueController(private val service: IssueService) {
private companion object : KLogging()
@Get(value = "/{issue-id}", produces = [MediaType.APPLICATION_JSON])
fun getById(@PathVariable("issue-id") id: String, context: HttpRequest<*>): HttpResponse<Issue> {
logger.info { "${context.uri} ${context.path}" }
return service.findById(UUID.fromString(id))
.map { HttpResponse.ok(it) }
.orElse(HttpResponse.notFound())
}
}
IssueService
а такжеIssue
не актуальны; Я могу опубликовать их, если так.
Каждый раз, когда я тестирую этот метод для "несуществующего" сценария (ов) - ветвь, которая выполняет .orElse(HttpResponse.notFound())
- Я получаю это в результате:
01-06-2019 15:15:15.278 |- DEBUG in DefaultHttpClient:1534 [nioEventLoopGroup-1-3] - Sending HTTP Request: GET /api/issues/22079988-7fbd-4f82-86b5-22b9534dc61b
01-06-2019 15:15:15.279 |- DEBUG in DefaultHttpClient:1535 [nioEventLoopGroup-1-3] - Chosen Server: localhost(9080)
01-06-2019 15:15:15.280 |- TRACE in DefaultHttpClient:1925 [nioEventLoopGroup-1-3] - Accept: application/json
01-06-2019 15:15:15.280 |- TRACE in DefaultHttpClient:1925 [nioEventLoopGroup-1-3] - host: localhost:9080
01-06-2019 15:15:15.280 |- TRACE in DefaultHttpClient:1925 [nioEventLoopGroup-1-3] - connection: close
01-06-2019 15:15:15.576 |- TRACE in DefaultHttpClient:1712 [nioEventLoopGroup-1-3] - HTTP Client Response Received for Request: GET http://localhost:9080/api/issues/22079988-7fbd-4f82-86b5-22b9534dc61b
01-06-2019 15:15:15.576 |- TRACE in DefaultHttpClient:1713 [nioEventLoopGroup-1-3] - Status Code: 404 Not Found
01-06-2019 15:15:15.576 |- TRACE in DefaultHttpClient:1925 [nioEventLoopGroup-1-3] - Date: Sun, 6 Jan 2019 15:15:15 GMT
01-06-2019 15:15:15.576 |- TRACE in DefaultHttpClient:1925 [nioEventLoopGroup-1-3] - connection: close
01-06-2019 15:15:15.576 |- TRACE in DefaultHttpClient:1904 [nioEventLoopGroup-1-3] - Response Body
01-06-2019 15:15:15.576 |- TRACE in DefaultHttpClient:1905 [nioEventLoopGroup-1-3] - ----
01-06-2019 15:15:15.576 |- TRACE in DefaultHttpClient:1906 [nioEventLoopGroup-1-3] -
01-06-2019 15:15:15.576 |- TRACE in DefaultHttpClient:1907 [nioEventLoopGroup-1-3] - ----
01-06-2019 15:15:15.577 |- TRACE in DefaultHttpClient:207 [nioEventLoopGroup-1-3] - Full HTTP response received an empty body
01-06-2019 15:15:15.577 |- TRACE in DefaultHttpClient:190 [nioEventLoopGroup-1-3] - Unable to convert response body to target type class java.lang.String
01-06-2019 15:15:15.579 |- ERROR in RecoveryInterceptor:206 [main] - Type [io.shido.http.IssueControllerTest$HttpClient$Intercepted] executed with error: Not Found
io.micronaut.http.client.exceptions.HttpClientResponseException: Not Found
at io.micronaut.http.client.DefaultHttpClient$10.channelRead0(DefaultHttpClient.java:1748)
at io.micronaut.http.client.DefaultHttpClient$10.channelRead0(DefaultHttpClient.java:1701)
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:189)
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.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
io.micronaut.http.client.exceptions.HttpClientResponseException: Not Found
at io.micronaut.http.client.DefaultHttpClient$10.channelRead0(DefaultHttpClient.java:1748)
at io.micronaut.http.client.DefaultHttpClient$10.channelRead0(DefaultHttpClient.java:1701)
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:189)
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.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
Я не очень хорошо знаю структуру, но я не ожидал бы исключения в этом случае. У меня есть что-то похожее в Spring Boot, и оно работает как положено. Более того, почему это: Unable to convert response body to target type class java.lang.String
?
Кто-нибудь знает, как это решить?
Это тестовый класс:
@MicronautTest
@Requires(env = [Environment.TEST])
internal class IssueControllerTest {
@Inject
private lateinit var client: HttpClient
@Test
fun `find (existing) record by identifier`() {
val id = "13f36c4e-c525-4d76-9831-b768c00345d2" // title-001
val result = client.getById(id)
Assertions.assertThat(result.status).isEqualTo(HttpStatus.OK)
Assertions.assertThat(result.body)
.isPresent
.hasValueSatisfying {
Assertions.assertThat(it.title).isEqualTo("title-001")
Assertions.assertThat(it.description).isEqualTo("description-001")
Assertions.assertThat(it.content).isEqualTo("content-001")
Assertions.assertThat(it.status).isEqualTo(Issue.Status.CREATED)
Assertions.assertThat(it.getId()).isEqualTo(id.asUuid())
Assertions.assertThat(it.version).isEqualTo(0)
}
}
@Test
fun `find (non-existent) record by identifier`() {
val result = client.getById(UUID.randomUUID().toString())
Assertions.assertThat(result.status).isEqualTo(HttpStatus.NOT_FOUND)
Assertions.assertThat(result.body).isNotPresent
}
@Client(value = "/api/issues")
private interface HttpClient {
@Get(value = "/{issue-id}")
fun getById(@PathVariable("issue-id") id: String): HttpResponse<Issue>
}
}
0 ответов
Вы пытались изменить имя PathVariable на "IssueId"? как это:
@Get(value = "/{issueId}")
fun getById(@PathVariable("issueId") issueId: String): HttpResponse<Issue>