アプリには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."}
この状況でJava.net.HttpRetryExceptionの原因は何ですか?
さらに:数回前、このメカニズムはうまくいきました。しかし、アプリ内の多くのコードを変更したためです。
SimpleClientHttpRequestFactory を使用すると、同じ問題に直面しました。設定して解決しました
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setOutputStreaming(false);
return requestFactory;
問題は、認証の場合のチャンク化とその後の再試行メカニズムが原因です。
HttpClientPolicyを使用してチャンクを無効にすることもできます
構成済みのHttpComponentsClientHttpRequestFactoryをRestTemplateに渡すと役立つと思います。 こちら 解決方法が見つかるかもしれません。
このような開発ソリューションを使用した理由は、401、404などのHttpエラー応答の本文の応答メッセージを処理し、アプリケーションを実サーバー側の環境にデプロイできるようにするためです。
この問題は、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>