簡體   English   中英

NoHttpResponseException作為運行時異常拋出,即使是已檢查的異常

[英]NoHttpResponseException thrown as runtime exception even though is a checked exception

我遇到一個奇怪的問題,即org.apache.http.NoHttpResponseException被拋出為未經檢查的異常,即使它是一個已檢查的異常,因為它擴展了java.io.IOException ...從下面的貼出的堆棧跟蹤可以看出我'我得到一個異常,應該在編譯時檢查為未經檢查的運行時異常。

我得到的異常的堆棧跟蹤如下(我的類在包中: 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文件dependecies聲明如下:

  <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>

產生這個結果:

Maven依賴樹

如果應該檢查此異常是否未經檢查,怎么可能? 這里有什么我想念的嗎?

注意

該異常並不總是可重現的,因為只有在亞馬遜服務缺少響應時才會在生產中發生。

更新

我已經驗證了AmazonHttpClient直到到達AmazonHttpClient類,而這個代碼正在捕獲`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 ...

stacktrace之前的行總是:

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 “在里面”。

你可以使用如下代碼片段來模擬這個:

throw new AmazonClientException("Oh no!", new NoHttpResponseException("The AWS server doesn't like you"));

如果我將這行代碼插入現有的Java應用程序(在本例中為Spring Boot),這就是我在Eclipse控制台中看到的:

沒有運行時異常的跡象

沒有AmazonClientException跡象! 直到,我滾動到右邊:

它就是

亞馬遜決定采用未經檢查的例外情況,並在此處進行記錄

所以他們確實(我很確定)將IOException包裝在運行時異常中,通過給你“對你處理的錯誤進行細粒度控制”來“幫助”你,盡管這並不總是顯而易見的。

總而言之,我可能是錯的。 如果我是對的,我希望在堆棧頂部看到你的自定義SqsReceiverException ,因為你確實捕獲了AmazonClientException

在堆棧跟蹤之前沒有標准輸出的最后幾行,很難確定。 如果我沒有標記,你可以發布它們嗎?

更新

您使用( AmazonHttpClient:496 )更新問題的行是打印堆棧跟蹤的行。 Throwable傳遞給log.info() ,將打印堆棧跟蹤。 包裝和重新拋出異常之前,將記錄此跟蹤。

所以這一點似乎被“吞噬”了:

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並避免四次循環。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM