web-dev-qa-db-ja.com

java.net.HttpRetryException:サーバー認証のため、ストリーミングモードで再試行できません

アプリには2つの部分があります。
サーバー-RESTサービスを提供
クライアント-Spring restTemplateを介してそれらを使用する

HTTPステータスに加えて、サーバーはエラーを詳細に説明するJSONを含むHTTPボディを返します。そのため、カスタムエラーハンドラーをrestTemplateに追加して、エラーとしてコード化されたエラーを処理します。これは、HTTPボディの解析に非常に役立ちます。

しかし、HTTP/1.1 401 Unauthorizedの場合、HTTP本文の解析を介して例外を受け取ります。他のすべてのエラーコードは正常に処理されます(400、402など)。エラーの場合にHTTP応答を送信する単純なサーバーロジックを使用します。さまざまなタイプのエラーに対する特別なルールはありません。

writeErrorToResponse(int status, String errMsg, HttpServletResponse resp) throws IOException {
        response.setStatus(status);
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        String message = String.format("{\"error\":\"%s\"}", StringUtils.escapeJson(errMsg));
        resp.getWriter().println(message);
    }

ただし、クライアントではHTTP/1.1 401のみが例外をスローします-"Java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode"

デバッグを行ったところ、問題の原因がSimpleClientHttpResponseのコードであることがわかりました。

HttpURLConnection.getInputStream()

Fiddlerでのトレースには、次の応答があります。クライアントでメッセージが正しく解析されます。

HTTP/1.1 402 Payment Required
X-Powered-By: Servlet/3.0
Content-Type: application/json
Content-Language: en-GB
Content-Length: 55
Connection: Close
Date: Sat, 25 May 2013 10:10:44 GMT
Server: WebSphere Application Server/8.0

{"error":"I cant find that user.  Please try again."}

そして、例外の原因であるメッセージ:

HTTP/1.1 401 Unauthorized
X-Powered-By: Servlet/3.0
Content-Type: application/json
Content-Language: en-GB
Content-Length: 55
Date: Sat, 25 May 2013 11:00:21 GMT
Server: WebSphere Application Server/8.0

{"error":"I cant find that user.  Please try again."}

この状況でJa​​va.net.HttpRetryExceptionの原因は何ですか?

さらに:数回前、このメカニズムはうまくいきました。しかし、アプリ内の多くのコードを変更したためです。

24
Oleksandr_DJ

SimpleClientHttpRequestFactory を使用すると、同じ問題に直面しました。設定して解決しました

SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setOutputStreaming(false);
return requestFactory;

問題は、認証の場合のチャンク化とその後の再試行メカニズムが原因です。

HttpClientPolicyを使用してチャンクを無効にすることもできます

23

構成済みのHttpComponentsClientHttpRequestFactoryをRestTemplateに渡すと役立つと思います。 こちら 解決方法が見つかるかもしれません。

このような開発ソリューションを使用した理由は、401、404などのHttpエラー応答の本文の応答メッセージを処理し、アプリケーションを実サーバー側の環境にデプロイできるようにするためです。

9
Youness

この問題は、Spring Frameworkで報告されています。

参照https://jira.spring.io/browse/SPR-9367

リファレンスからのコピー:RestTemplateで401応答をデフォルト設定で処理することは非常に困難です(不可能です)。実際には可能ですが、エラーハンドラとリクエストファクトリを提供する必要があります。エラーハンドラーは明らかでしたが、問題は、応答のステータスコードを確認しようとするとHttpRetryExceptionをスローする可能性のあるJava.netをデフォルトのリクエストファクトリが使用することです(明らかに使用可能ですが)。解決策は、HttpComponentsClientHttpRequestFactoryを使用することです。例えば。

template.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
template.setErrorHandler(new DefaultResponseErrorHandler() {
    public boolean hasError(ClientHttpResponse response) throws IOException {
        HttpStatus statusCode = response.getStatusCode();
        return statusCode.series() == HttpStatus.Series.SERVER_ERROR;
    }
});

HttpComponentsClientHttpRequestFactoryには以下の依存関係が必要です。 POMファイルに以下の依存関係を追加します。

<dependency>
            <groupId>org.Apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
</dependency>
4
Hemanth