首页 > 解决方案 > Apache httpClient在忽略超时时重试POST请求

问题描述

我目前正在尝试构建一个向定义的 API 发送 POST 请求的 OSGi 服务。此 API 用于对请求正文 (JSON) 中作为 Base64 字符串包含的文件进行病毒扫描。为此,我使用 Adob​​e AEM uberjar v6.4.0 中包含的 Apache HttpClient

我当前的实现适用于较小的文件(<2 MB),但随着文件大小变大,行为变得奇怪: 当我上传 9 MB 文件时,请求执行约 1 分钟,然后获得 HTTP400 作为响应,然后重试请求 7 次。

我尝试对请求使用超时。如果超时低于 60.000 毫秒,则会引发 TimeoutException,如果大于 60.000 毫秒,则会收到 HTTP400 错误请求。我想后者是我需要澄清的 API 错误。

但是,在引发异常后的这两种情况下,httpClient 都会重试请求,但我无法阻止这种情况发生。我正在与网络上许多已弃用的“HowTo”作斗争,现在我在这里。

我稍微缩短了代码,因为它有点大(主要是在开头删除调试消息和一些“如果...返回 false”)。我的代码:

public boolean isAttachmentClean(InputStream inputStream) throws IOException, JSONException, ServiceUnavailableException {

    //prevent httpClient from retrying in case of an IOException
    final HttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler(0, false);
    HttpClient httpClient = HttpClients.custom().setRetryHandler(retryHandler).build();
    HttpPost httpPost = new HttpPost(serviceUrl);

    httpPost.setHeader("accept", "application/json");
    //set some more headers...

    //set timeout for POST from OSGi Config
    RequestConfig timeoutConfig = RequestConfig.custom()
            .setConnectionRequestTimeout(serviceTimeout)
            .setConnectTimeout(serviceTimeout)
            .setSocketTimeout(serviceTimeout)
            .build();
    httpPost.setConfig(timeoutConfig);

    //create request body data
    String requestBody;
    try {
        requestBody = buildDataJson(inputStream);
    } finally {
        inputStream.close();
    }
    HttpEntity requestBodyEntity = new ByteArrayEntity(requestBody.getBytes("UTF-8"));
    httpPost.setEntity(requestBodyEntity);

    //Execute and get the response.
    HttpResponse response = httpClient.execute(httpPost);

    if (response.getStatusLine().getStatusCode() != HttpServletResponse.SC_OK){
        httpPost.abort();
        throw new ServiceUnavailableException("API not available, Response Code was "+ response.getStatusLine().getStatusCode());
    }
    HttpEntity entity = response.getEntity();

    boolean result = false;
    if (entity != null) {
        InputStream apiResult = entity.getContent();
        try {

            // check the response from the API (Virus yes or no)
            result = evaluateResponse(apiResult);
        } finally {
            apiResult.close();
        }
    }
    return result;
}

“buildDataJson()”只是读取 InputStream 并创建 API 调用所需的 JSON。“evaluateResponse()”还读取 InputStream,将其转换为 JSON 并检查名为“Status:”“Clean”的属性。

我将不胜感激有关为什么一遍又一遍地重试此请求的任何提示。

/edit:到目前为止,我发现 Apache httpClient 有一些默认机制,可以在 IOException 的情况下重试请求——这就是我在这里得到的。尽管如此,我还没有找到关于如何停用这些重试的解决方案。

标签: javaapachepostaem

解决方案


推荐阅读