HttpClient 在响应代码 404 上抛出异常。这是设计使然还是我做错了什么?
HttpClient throws exception on response code 404. Is this by design or am I doing something wrong?
我今天开始使用 Micronaut。
我构建了这个控制器:
@Controller
public class MyController implements MyApi{
@Override
public String doit() {
throw new NotFoundException();
}
}
和这个异常处理程序:
@Produces
@Singleton
@Requires(classes = { NotFoundException.class, ExceptionHandler.class})
public class NotFoundExceptionHandler implements ExceptionHandler<NotFoundException, HttpResponse> {
@Override
public HttpResponse handle(HttpRequest request, NotFoundException exception) {
return HttpResponseFactory.INSTANCE.status(HttpStatus.NOT_FOUND);
}
}
而这个测试:
@MicronautTest
public class MyControllerIT {
@Inject
@Client("/")
HttpClient client;
@Test
public void testHello() {
HttpRequest<String> request = HttpRequest.GET("/myController");
HttpResponse<String> body = client.toBlocking().exchange(request);
assertThat(body.getStatus(), is(HttpStatus.NOT_FOUND));
}
}
我的期望是它会通过:我会收到没有内容的响应,HTTP 代码 404,消息 "Not found",然后我就完成了。
但是,相反,我得到:
io.micronaut.http.client.exceptions.HttpClientResponseException: Not Found
at io.micronaut.http.client.DefaultHttpClient.channelRead0(DefaultHttpClient.java:1799)
at io.micronaut.http.client.DefaultHttpClient.channelRead0(DefaultHttpClient.java:1739)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.micronaut.http.netty.stream.HttpStreamsHandler.channelRead(HttpStreamsHandler.java:185)
at io.micronaut.http.netty.stream.HttpStreamsClientHandler.channelRead(HttpStreamsClientHandler.java:180)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:328)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:302)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:287)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1421)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:697)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:632)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:549)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:511)
at io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:918)
at io.netty.util.internal.ThreadExecutorMap.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:834)
我找到了描述 An exception that occurs when a response returns an error code equal to or greater than 400.
的 HttpClientResponseException 文档
这真的是预期的行为吗?当错误代码 > 400 时,它迫使我将其作为异常处理,这似乎有点奇怪。
我是不是设置有误?
我认为您的代码没有问题。此特定异常的文档明确指出:
An exception that occurs when a response returns an error code equal to or greater than 400.
如果您不满意,我们可以深入挖掘。在名为 channelRead0
的方法中 DefaultHttpClient
class 中抛出异常。让我们看看我们能在那里找到什么。
boolean errorStatus = statusCode >= 400;
if (errorStatus) {
emitter.onError(new HttpClientResponseException(response.getStatus().getReason(), response));
} else {
emitter.onNext(response);
emitter.onComplete();
}
这个异常被进一步传递,看起来它最终被抛到了某个地方。就是这样工作的,这是作者的设计。如果你不喜欢它,你可以随时使用旧的内置 HttpURLConnection, a new HttpClient from Java 9 or something 3rd party like OkHttp.
我今天开始使用 Micronaut。 我构建了这个控制器:
@Controller
public class MyController implements MyApi{
@Override
public String doit() {
throw new NotFoundException();
}
}
和这个异常处理程序:
@Produces
@Singleton
@Requires(classes = { NotFoundException.class, ExceptionHandler.class})
public class NotFoundExceptionHandler implements ExceptionHandler<NotFoundException, HttpResponse> {
@Override
public HttpResponse handle(HttpRequest request, NotFoundException exception) {
return HttpResponseFactory.INSTANCE.status(HttpStatus.NOT_FOUND);
}
}
而这个测试:
@MicronautTest
public class MyControllerIT {
@Inject
@Client("/")
HttpClient client;
@Test
public void testHello() {
HttpRequest<String> request = HttpRequest.GET("/myController");
HttpResponse<String> body = client.toBlocking().exchange(request);
assertThat(body.getStatus(), is(HttpStatus.NOT_FOUND));
}
}
我的期望是它会通过:我会收到没有内容的响应,HTTP 代码 404,消息 "Not found",然后我就完成了。
但是,相反,我得到:
io.micronaut.http.client.exceptions.HttpClientResponseException: Not Found
at io.micronaut.http.client.DefaultHttpClient.channelRead0(DefaultHttpClient.java:1799)
at io.micronaut.http.client.DefaultHttpClient.channelRead0(DefaultHttpClient.java:1739)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.micronaut.http.netty.stream.HttpStreamsHandler.channelRead(HttpStreamsHandler.java:185)
at io.micronaut.http.netty.stream.HttpStreamsClientHandler.channelRead(HttpStreamsClientHandler.java:180)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:328)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:302)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:287)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1421)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:697)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:632)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:549)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:511)
at io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:918)
at io.netty.util.internal.ThreadExecutorMap.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:834)
我找到了描述 An exception that occurs when a response returns an error code equal to or greater than 400.
这真的是预期的行为吗?当错误代码 > 400 时,它迫使我将其作为异常处理,这似乎有点奇怪。
我是不是设置有误?
我认为您的代码没有问题。此特定异常的文档明确指出:
An exception that occurs when a response returns an error code equal to or greater than 400.
如果您不满意,我们可以深入挖掘。在名为 channelRead0
的方法中 DefaultHttpClient
class 中抛出异常。让我们看看我们能在那里找到什么。
boolean errorStatus = statusCode >= 400;
if (errorStatus) {
emitter.onError(new HttpClientResponseException(response.getStatus().getReason(), response));
} else {
emitter.onNext(response);
emitter.onComplete();
}
这个异常被进一步传递,看起来它最终被抛到了某个地方。就是这样工作的,这是作者的设计。如果你不喜欢它,你可以随时使用旧的内置 HttpURLConnection, a new HttpClient from Java 9 or something 3rd party like OkHttp.