2017-10-15 3 views
3

返されたステータスコードに基づいて例外をスローしようとすると、どのように応答本体を取得しますか?例えば、私は詳細なWebClientResponseExceptionを投げることができるので、どのように私は、応答者の身体に例外を取り込むことができますか?HTTP 201WebFlux WebClientでステータスコードをテストするときに応答本文を取得するにはどうすればよいですか?

client.post().exchange().doOnSuccess(response -> { 
    if (response.statusCode().value() == 201) { 
     throw new RuntimeException(); 
    } 
} 

私は例外をスローし、拒否したいと言うことができますか

応答ステータスコードをテストするために別の方法を使用する必要がありますか?

編集:代わりにexchange()を使用しているときに、次の機能を複製しようとしています。

client.get() 
    .retrieve() 
    .onStatus(s -> !HttpStatus.CREATED.equals(s), 
     MyClass::createResponseException); 

//MyClass 
public static Mono<WebClientResponseException> createResponseException(ClientResponse response) { 
    return response.body(BodyExtractors.toDataBuffers()) 
      .reduce(DataBuffer::write) 
      .map(dataBuffer -> { 
       byte[] bytes = new byte[dataBuffer.readableByteCount()]; 
       dataBuffer.read(bytes); 
       DataBufferUtils.release(dataBuffer); 
       return bytes; 
      }) 
      .defaultIfEmpty(new byte[0]) 
      .map(bodyBytes -> { 
       String msg = String.format("ClientResponse has erroneous status code: %d %s", response.statusCode().value(), 
         response.statusCode().getReasonPhrase()); 
       Charset charset = response.headers().contentType() 
         .map(MimeType::getCharset) 
         .orElse(StandardCharsets.ISO_8859_1); 
       return new WebClientResponseException(msg, 
         response.statusCode().value(), 
         response.statusCode().getReasonPhrase(), 
         response.headers().asHttpHeaders(), 
         bodyBytes, 
         charset 
         ); 
      }); 
} 

答えて

2

doOn**演算子は、副作用演算子であり、例えば、ロギング目的で使用する必要があります。ここで

、あなたはパイプラインレベルでその動作を実装したいと思いますので、onStatusが良く、ここでフィットのようになります。

Mono<ClientHttpResponse> clientResponse = client.post().uri("/resource") 
    .retrieve() 
    .onStatus(httpStatus -> HttpStatus.CREATED.equals(httpStatus), 
     response -> response.bodyToMono(String.class).map(body -> new MyException(body))) 
    bodyToXYZ(...); 

それとも

Mono<ResponseEntity<String>> result = client.post().uri("/resource") 
    .exchange() 
    .flatMap(response -> response.toEntity(String.class)) 
    .flatMap(entity -> { 
     // return Mono.just(entity) or Mono.error() depending on the response 
    }); 

。なお、全レスポンスボディを取得大きなレスポンスボディを期待するなら、良い考えではないかもしれません。その場合、大量のデータをバッファリングすることになります。

+0

申し訳ありませんが、私は実際に 'ClientResponse'にアクセスできるように' exchange() 'を使いたいと思っていました。 'onStatus()'と同じ機能を他の方法で実行できますか?その方法は利用できませんか? – CoryO

+0

には、あなたのユースケースに合った代替ソリューションが追加されていますが、なぜClientResponseへのアクセスが好きなのかわかりません。それをクライアントの 'ExchangeFilterFunction'として設定しますか? –

+0

私はうまくいけば私が何をしているのかをより明確に示すために質問を編集しました。 – CoryO

-1

試行錯誤の結果、私はこのトリックを行うように見える次のことができました。

Mono<ClientResponse> mono = client.get().exchange() 
     .flatMap(response -> { 
      if (HttpStatus.CREATED.equals(response.statusCode())) { 
       return Mono.just(response); 
      } else { 
       return response.body(BodyExtractors.toDataBuffers()) 
         .reduce(DataBuffer::write) 
         .map(dataBuffer -> { 
          byte[] bytes = new byte[dataBuffer.readableByteCount()]; 
          dataBuffer.read(bytes); 
          DataBufferUtils.release(dataBuffer); 
          return bytes; 
         }) 
         .defaultIfEmpty(new byte[0]) 
         .flatMap(bodyBytes -> { 
          String msg = String.format("ClientResponse has erroneous status code: %d %s", response.statusCode().value(), 
            response.statusCode().getReasonPhrase()); 
          Charset charset = response.headers().contentType() 
            .map(MimeType::getCharset) 
            .orElse(StandardCharsets.ISO_8859_1); 
          return Mono.error(new WebClientResponseException(msg, 
            response.statusCode().value(), 
            response.statusCode().getReasonPhrase(), 
            response.headers().asHttpHeaders(), 
            bodyBytes, 
            charset 
            )); 
         }); 
      } 
     }) 
     .retry(3); 
final CompletableFuture<ClientResponse> future = mono.toFuture(); 
-1

カスタムExchangeFilterFunctionを有し、かつ、あなたがWebクライアントを構築する前にWebClient.Builderでこれをフックすることで、このように達成できます。

public static ExchangeFilterFunction errorHandlingFilter() { 
     return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> { 
      if(clientResponse.statusCode()!=null && (clientResponse.statusCode().is5xxServerError() || clientResponse.statusCode().is4xxClientError())) { 
       return clientResponse.bodyToMono(String.class) 
         .flatMap(errorBody -> { 
          return Mono.error(new CustomWebClientResponseException(errorBody,clientResponse.statusCode())); 
          }); 
      }else { 
       return Mono.just(clientResponse); 
      } 
     }); 
    } 

あなたはこのように上記使用することができます。

WebClient.builder() 
       .clientConnector(new ReactorClientHttpConnector(clientOptions)) 
       .defaultHeader(HttpHeaders.USER_AGENT, "Application") 
       .filter(WebClientUtil.errorHandlingFilter()) 
       .baseUrl("https://httpbin.org/") 
       .build() 
       .post() 
       .uri("/post") 
       .body(BodyInserters.fromObject(customObjectReference)) 
       .exchange() 
       .flatMap(response -> response.toEntity(String.class)); 

だから、任意の4XXまたは5XXのHttpResponse実際CustomWebClientResponseExceptionがスローされますし、あなたには、いくつかのグローバル例外ハンドラを設定し、これにしたいものを行うことができます。 ExchangeFilterFunctionを使用しても、このようなことを処理するグローバルな場所を持つことも、カスタムヘッダーやアイテムを追加することもできます。

関連する問題