SpringのRestTemplate
とJacksonを使用してRESTful JSON APIを使用しています。場合によっては、Status 401
(認証されていない)応答、カスタムJSONボディ、これはAPIメーカーによって定義され、次のようになります。
{
"code": 123,
"message": "Reason for the error"
}
本文を解析し、ビジネスロジックでcode
プロパティを使用する必要があります。
これはエラー応答ですJava解析する必要があるオブジェクト:
public class CustomError {
@JsonProperty
private Integer code;
@JsonProperty
private String message;
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}
これを行うカスタムエラーハンドラ:
public class CustomErrorHandler extends DefaultResponseErrorHandler {
private RestTemplate restTemplate;
private ObjectMapper objectMapper;
private MappingJacksonHttpMessageConverter messageConverter;
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
return super.hasError(response);
}
@Override
public void handleError(final ClientHttpResponse response) throws IOException {
try {
CustomError error =
(CustomError) messageConverter.read(CustomError.class, response);
throw new CustomErrorIOException(error, error.getMessage());
} catch (Exception e) {
// parsing failed, resort to default behavior
super.handleError(response);
}
}
}
エラーハンドラーは、tryブロックでHttpMessageNotReadableException
で失敗します。
「JSONを読み取れませんでした:サーバー認証のため、ストリーミングモードで再試行できません」
これは私がリクエストを送信する方法です:
restTemplate.postForObject(url, pojoInstance, responseClass);
同じ要求がPostmanなどの単純な古いRESTクライアントプログラムで実行された場合、予想されるJSON応答が受信されます。そのため、401ステータスの場合、SpringのClientHttpResponse
実装が何らかの形で応答本文へのアクセスを許可しない可能性があると考えられます。
応答本文を解析することは実際に可能ですか?
更新
私が調べたところから、RestTemplate
クラスはClientHttpResponse
を使用し、これがSun.net.www.protocol.http.HttpURLConnection
入力ストリームを提供します。入力ストリームが無視され、IOException
がスローされる場所があります。
サーバー認証のため、ストリーミングモードで再試行できません
そのため、HttpURLConnection
の実装が問題を引き起こしています。
この問題を回避することは可能ですか?おそらく、エラーステータスコードの場合に応答本文を無視しない代替実装を使用する必要がありますか?他の選択肢を推奨できますか?
カスタムハンドラを必要とせずに次のアプローチを試してください。これは、HttpStatusCodeExceptionから文字列として応答を取得し、それをオブジェクトに変換するという考え方です。変換には、ジャクソンのObjectMapperを使用しました。
try {
restTemplate.postForObject(url, pojoInstance, responseClass);
} catch (HttpStatusCodeException e) {
if (e.getStatusCode() == HttpStatus.UNAUTHORIZED) {
String responseString = e.getResponseBodyAsString();
ObjectMapper mapper = new ObjectMapper();
CustomError result = mapper.readValue(responseString,
CustomError.class);
}
}
更新:問題に関連するデフォルトのバグがあるため、別のファクトリの使用も役立つ場合があります(以下のコメントを参照)。
RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory());