java - HttpClient 在响应代码 404 上引发异常。这是设计使然还是我做错了什么?
问题描述
我今天从 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,消息“未找到”,我会完成的。
但是,相反,我得到:
io.micronaut.http.client.exceptions.HttpClientResponseException: Not Found
at io.micronaut.http.client.DefaultHttpClient$10.channelRead0(DefaultHttpClient.java:1799)
at io.micronaut.http.client.DefaultHttpClient$10.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$5.run(SingleThreadEventExecutor.java:918)
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:834)
我发现这个HttpClientResponseException文档描述了An exception that occurs when a response returns an error code equal to or greater than 400.
这真的是预期的行为吗?当错误代码> 400时,它迫使我将其作为异常处理,这似乎有点奇怪。
我在设置中做错了吗?
解决方案
我认为您的代码没有问题。这个特殊例外的文档清楚地指出:
当响应返回等于或大于 400 的错误代码时发生的异常。
如果这对您不满意,我们可以深入挖掘。异常在DefaultHttpClient
名为 的方法中的类中引发channelRead0
。让我们看看我们能在那里找到什么。
boolean errorStatus = statusCode >= 400;
if (errorStatus) {
emitter.onError(new HttpClientResponseException(response.getStatus().getReason(), response));
} else {
emitter.onNext(response);
emitter.onComplete();
}
这个异常被进一步传递,看起来它最终被抛出到某个地方。它只是这样工作,这是作者的设计。如果您不喜欢它,您可以随时使用旧的内置HttpURLConnection、Java 9 中的新HttpClient或像OkHttp这样的第 3 方。
推荐阅读
- jqgrid - 如何在 Jqgrid 中隐藏导航栏并使用新值动态重新加载
- regex - 如何提取点(。)结尾的句子?
- python - 改变张量的某一列的值
- configure - autoreconf:需要“configure.ac”或“configure.in”
- c++ - cpp修改中的引用变量
- ios - 应用程序从挂起状态终止后,应用程序界面快照短暂闪烁
- oracle - ORA-06508 调用远程数据库上的过程时
- qt - QML 将信号连接到功能
- asterisk - Asterisk Dialplan AGI 脚本未执行(可能是 Asterisk 权限问题?)
- php - MailChimp API v3 - 无法修补/更新?