NoHttpResponseException 作为运行时异常抛出,即使是已检查的异常
NoHttpResponseException thrown as runtime exception even though is a checked exception
我遇到了一个奇怪的问题,其中 org.apache.http.NoHttpResponseException
被抛出为未经检查的异常,尽管它是一个已检查的异常,因为它扩展了 java.io.IOException
... 从下面的帖子中可以看出stacktrace 我收到一个异常,应该在编译时将其作为未经检查的运行时异常进行检查。
我得到的异常的堆栈跟踪如下(我的classes在包中:com.example.staticsite
):
org.apache.http.NoHttpResponseException: sqs.eu-west-1.amazonaws.com failed to respond
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:143)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:57)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:260)
at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:283)
at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:251)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.receiveResponseHeader(ManagedClientConnectionImpl.java:197)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:271)
at com.amazonaws.http.protocol.SdkHttpRequestExecutor.doReceiveResponse(SdkHttpRequestExecutor.java:66)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:123)
at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:685)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:487)
at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:863)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:57)
at com.amazonaws.http.AmazonHttpClient.executeOneRequest(AmazonHttpClient.java:728)
at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:489)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:310)
at com.amazonaws.services.sqs.AmazonSQSClient.invoke(AmazonSQSClient.java:2419)
at com.amazonaws.services.sqs.AmazonSQSClient.receiveMessage(AmazonSQSClient.java:1130)
at com.example.staticsite.aws.SqsReceiverImpl.receiveReceipt(SqsReceiverImpl.java:57)
at com.example.staticsite.core.processsite.ProcessSiteImpl.runOneTime(ProcessSiteImpl.java:59)
at com.example.staticsite.core.processsite.ProcessSiteImpl.run(ProcessSiteImpl.java:44)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:473)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:622)
at java.lang.Thread.run(Thread.java:748)
在我的代码中抛出异常的方法是:
public class SqsReceiverImpl implements SqsReceiver {
private AmazonSQS client;
private String queueUrl;
@Inject
public SqsReceiverImpl(AmazonSQS client,@Assisted String queueUrl) {
this.client = client;
this.queueUrl = queueUrl;
}
public List<String> receiveReceipt() throws SqsReceiverException {
if(queueUrl == null)
throw new SqsReceiverException(SqsReceiverException.MESSAGE_NO_QUEURURL);
ReceiveMessageRequest request = new ReceiveMessageRequest();
request.setMaxNumberOfMessages(10);
request.setQueueUrl(queueUrl);
request.setWaitTimeSeconds(20);
ReceiveMessageResult results = null;
try {
results = client.receiveMessage(request);
}
catch(OverLimitException oe){
throw new SqsReceiverException("OverLimitException thrown");
}
catch(AmazonServiceException oe){
throw new SqsReceiverException("AmazonServiceException thrown");
}
catch(AmazonClientException oe){
throw new SqsReceiverException("AmazonClientException thrown");
}
SqsReceiverException
定义如下:
public class SqsReceiverException extends Exception{
public SqsReceiverException(String messageNoQueururl) {
super(messageNoQueururl);
}
public static final String MESSAGE_NO_QUEURURL = "Queue url not found. Se the queue url";
}
pom文件依赖声明如下:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-sqs</artifactId>
<version>1.10.12</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-assistedinject</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
</dependencies>
生成此结果:
这个异常在应该被检查的时候怎么可能被威胁为未检查?
我在这里遗漏了什么吗?
备注
异常并不总是可重现的,因为它只在亚马逊服务缺少响应时发生在生产中。
更新
我已经验证了堆栈跟踪,直到到达 AmazonHttpClient
class 而这段代码正在捕获“IOException”:
catch (IOException ioe) {
if (log.isInfoEnabled()) {
log.info("Unable to execute HTTP request: " + ioe.getMessage(), ioe);
}
captureExceptionMetrics(ioe, awsRequestMetrics);
awsRequestMetrics.addProperty(AWSRequestID, null);
AmazonClientException ace = new AmazonClientException(
"Unable to execute HTTP request: " + ioe.getMessage(),
ioe);
if (!shouldRetry(request.getOriginalRequest(),
p.apacheRequest,
ace,
p.requestCount,
config.getRetryPolicy())) {
throw lastReset(ace, request);
}
// Cache the retryable exception
p.retriedException = ace;
}
而 lastReset
应该是引发异常的原因,我不明白的是记录的异常怎么可能是 org.apache.http.NoHttpResponseException
...
堆栈跟踪之前的行始终是:
2017-09-15 07:41:39 INFO AmazonHttpClient:496 - Unable to execute HTTP request: sqs.eu-west-1.amazonaws.com failed to respond
我猜你是堆栈跟踪格式化的受害者。
我认为当您指责 lastReset()
是罪魁祸首时,您是对的。这是您看到 throws IOException
从堆栈跟踪中消失的地方。这个方法很明显是抛出一个AmazonClientException
(运行时异常),用原来的NoHttpResponseException
"inside"吧。
您可以使用如下代码片段来模拟:
throw new AmazonClientException("Oh no!", new NoHttpResponseException("The AWS server doesn't like you"));
如果我将这行代码插入现有的 Java 应用程序(Spring Boot,在这种情况下),这就是我在 Eclipse 控制台中看到的:
没有迹象AmazonClientException
!直到,我向右滚动:
亚马逊决定采用未经检查的异常,documented it here。
所以他们确实(我很确定)将你的 IOException
包装在运行时异常中,通过给你 "fine-grained control over the errors you handle" 给你 "help",尽管这并不总是显而易见。
综上所述,我可能是错的。如果我是对的,我希望在堆栈的顶部看到您的自定义 SqsReceiverException
,因为您确实捕获了 AmazonClientException
.
如果没有堆栈跟踪之前标准输出的最后几行,很难确定。如果我跑题了,你能 post 他们吗?
更新
您用 (AmazonHttpClient:496
) 更新问题的行是打印堆栈跟踪的行。当您将 Throwable
传递给 log.info()
时,将打印堆栈跟踪。此跟踪记录 在 您的异常被包装并重新抛出之前。
所以这个位似乎是 "swallowed":
com.amazonaws.AmazonClientException: Unable to execute HTTP request: sqs.us-east-1.amazonaws.com failed to respond
at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:500)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:310)
at com.amazonaws.services.sqs.AmazonSQSClient.invoke(AmazonSQSClient.java:2419)
at com.amazonaws.services.sqs.AmazonSQSClient.receiveMessage(AmazonSQSClient.java:1130)
at httptest.Main.main(Main.java:32)
Caused by:
而且我无法与失踪的 SqsReceiverException
交谈。但我不认为 DefaultRequestDirector.execute()
的签名在撒谎,我也不认为我们在处理编译器错误。
也许您可以将 oe.printStackTrace()
添加到您的 catch (AmazonClientException oe)
块?
最后,我建议使用调试器单步执行此操作。要模拟您的生产问题,只需在 DefaultHttpResponseParser:140
处设置一个断点,并在该行执行后,将 i
更改为 -1。然后返回堆栈一直返回到您的代码。
我还在 AmazonHttpClient:971
处设置了一个断点,这样我就可以更改 retries
并避免循环四次。
我遇到了一个奇怪的问题,其中 org.apache.http.NoHttpResponseException
被抛出为未经检查的异常,尽管它是一个已检查的异常,因为它扩展了 java.io.IOException
... 从下面的帖子中可以看出stacktrace 我收到一个异常,应该在编译时将其作为未经检查的运行时异常进行检查。
我得到的异常的堆栈跟踪如下(我的classes在包中:com.example.staticsite
):
org.apache.http.NoHttpResponseException: sqs.eu-west-1.amazonaws.com failed to respond
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:143)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:57)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:260)
at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:283)
at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:251)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.receiveResponseHeader(ManagedClientConnectionImpl.java:197)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:271)
at com.amazonaws.http.protocol.SdkHttpRequestExecutor.doReceiveResponse(SdkHttpRequestExecutor.java:66)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:123)
at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:685)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:487)
at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:863)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:57)
at com.amazonaws.http.AmazonHttpClient.executeOneRequest(AmazonHttpClient.java:728)
at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:489)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:310)
at com.amazonaws.services.sqs.AmazonSQSClient.invoke(AmazonSQSClient.java:2419)
at com.amazonaws.services.sqs.AmazonSQSClient.receiveMessage(AmazonSQSClient.java:1130)
at com.example.staticsite.aws.SqsReceiverImpl.receiveReceipt(SqsReceiverImpl.java:57)
at com.example.staticsite.core.processsite.ProcessSiteImpl.runOneTime(ProcessSiteImpl.java:59)
at com.example.staticsite.core.processsite.ProcessSiteImpl.run(ProcessSiteImpl.java:44)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:473)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:622)
at java.lang.Thread.run(Thread.java:748)
在我的代码中抛出异常的方法是:
public class SqsReceiverImpl implements SqsReceiver {
private AmazonSQS client;
private String queueUrl;
@Inject
public SqsReceiverImpl(AmazonSQS client,@Assisted String queueUrl) {
this.client = client;
this.queueUrl = queueUrl;
}
public List<String> receiveReceipt() throws SqsReceiverException {
if(queueUrl == null)
throw new SqsReceiverException(SqsReceiverException.MESSAGE_NO_QUEURURL);
ReceiveMessageRequest request = new ReceiveMessageRequest();
request.setMaxNumberOfMessages(10);
request.setQueueUrl(queueUrl);
request.setWaitTimeSeconds(20);
ReceiveMessageResult results = null;
try {
results = client.receiveMessage(request);
}
catch(OverLimitException oe){
throw new SqsReceiverException("OverLimitException thrown");
}
catch(AmazonServiceException oe){
throw new SqsReceiverException("AmazonServiceException thrown");
}
catch(AmazonClientException oe){
throw new SqsReceiverException("AmazonClientException thrown");
}
SqsReceiverException
定义如下:
public class SqsReceiverException extends Exception{
public SqsReceiverException(String messageNoQueururl) {
super(messageNoQueururl);
}
public static final String MESSAGE_NO_QUEURURL = "Queue url not found. Se the queue url";
}
pom文件依赖声明如下:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-sqs</artifactId>
<version>1.10.12</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-assistedinject</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
</dependencies>
生成此结果:
这个异常在应该被检查的时候怎么可能被威胁为未检查? 我在这里遗漏了什么吗?
备注
异常并不总是可重现的,因为它只在亚马逊服务缺少响应时发生在生产中。
更新
我已经验证了堆栈跟踪,直到到达 AmazonHttpClient
class 而这段代码正在捕获“IOException”:
catch (IOException ioe) {
if (log.isInfoEnabled()) {
log.info("Unable to execute HTTP request: " + ioe.getMessage(), ioe);
}
captureExceptionMetrics(ioe, awsRequestMetrics);
awsRequestMetrics.addProperty(AWSRequestID, null);
AmazonClientException ace = new AmazonClientException(
"Unable to execute HTTP request: " + ioe.getMessage(),
ioe);
if (!shouldRetry(request.getOriginalRequest(),
p.apacheRequest,
ace,
p.requestCount,
config.getRetryPolicy())) {
throw lastReset(ace, request);
}
// Cache the retryable exception
p.retriedException = ace;
}
而 lastReset
应该是引发异常的原因,我不明白的是记录的异常怎么可能是 org.apache.http.NoHttpResponseException
...
堆栈跟踪之前的行始终是:
2017-09-15 07:41:39 INFO AmazonHttpClient:496 - Unable to execute HTTP request: sqs.eu-west-1.amazonaws.com failed to respond
我猜你是堆栈跟踪格式化的受害者。
我认为当您指责 lastReset()
是罪魁祸首时,您是对的。这是您看到 throws IOException
从堆栈跟踪中消失的地方。这个方法很明显是抛出一个AmazonClientException
(运行时异常),用原来的NoHttpResponseException
"inside"吧。
您可以使用如下代码片段来模拟:
throw new AmazonClientException("Oh no!", new NoHttpResponseException("The AWS server doesn't like you"));
如果我将这行代码插入现有的 Java 应用程序(Spring Boot,在这种情况下),这就是我在 Eclipse 控制台中看到的:
没有迹象AmazonClientException
!直到,我向右滚动:
亚马逊决定采用未经检查的异常,documented it here。
所以他们确实(我很确定)将你的 IOException
包装在运行时异常中,通过给你 "fine-grained control over the errors you handle" 给你 "help",尽管这并不总是显而易见。
综上所述,我可能是错的。如果我是对的,我希望在堆栈的顶部看到您的自定义 SqsReceiverException
,因为您确实捕获了 AmazonClientException
.
如果没有堆栈跟踪之前标准输出的最后几行,很难确定。如果我跑题了,你能 post 他们吗?
更新
您用 (AmazonHttpClient:496
) 更新问题的行是打印堆栈跟踪的行。当您将 Throwable
传递给 log.info()
时,将打印堆栈跟踪。此跟踪记录 在 您的异常被包装并重新抛出之前。
所以这个位似乎是 "swallowed":
com.amazonaws.AmazonClientException: Unable to execute HTTP request: sqs.us-east-1.amazonaws.com failed to respond
at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:500)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:310)
at com.amazonaws.services.sqs.AmazonSQSClient.invoke(AmazonSQSClient.java:2419)
at com.amazonaws.services.sqs.AmazonSQSClient.receiveMessage(AmazonSQSClient.java:1130)
at httptest.Main.main(Main.java:32)
Caused by:
而且我无法与失踪的 SqsReceiverException
交谈。但我不认为 DefaultRequestDirector.execute()
的签名在撒谎,我也不认为我们在处理编译器错误。
也许您可以将 oe.printStackTrace()
添加到您的 catch (AmazonClientException oe)
块?
最后,我建议使用调试器单步执行此操作。要模拟您的生产问题,只需在 DefaultHttpResponseParser:140
处设置一个断点,并在该行执行后,将 i
更改为 -1。然后返回堆栈一直返回到您的代码。
我还在 AmazonHttpClient:971
处设置了一个断点,这样我就可以更改 retries
并避免循环四次。