protected Mono<Info> convertInfo(Instance instance, ClientResponse response) { if (response.statusCode().is2xxSuccessful() && response.headers() .contentType() .map(mt -> mt.isCompatibleWith(MediaType.APPLICATION_JSON) || mt.isCompatibleWith(ACTUATOR_V2_MEDIATYPE)) .orElse(false)) { return response.bodyToMono(RESPONSE_TYPE).map(Info::from).defaultIfEmpty(Info.empty()); } log.info("Couldn't retrieve info for {}: {}", instance, response.statusCode()); return response.bodyToMono(Void.class).then(Mono.just(Info.empty())); }
@Override public <T> Flux<T> bodyToFlux(ParameterizedTypeReference<T> typeReference) { return this.delegate.bodyToFlux(typeReference); }
private static Mono<WebClientResponseException> createResponseException( ClientResponse response, HttpRequest request) { return DataBufferUtils.join(response.body(BodyExtractors.toDataBuffers())) .map(dataBuffer -> { byte[] bytes = new byte[dataBuffer.readableByteCount()]; .defaultIfEmpty(new byte[0]) .map(bodyBytes -> { Charset charset = response.headers().contentType() .map(MimeType::getCharset) .orElse(StandardCharsets.ISO_8859_1); if (HttpStatus.resolve(response.rawStatusCode()) != null) { return WebClientResponseException.create( response.statusCode().value(), response.statusCode().getReasonPhrase(), response.headers().asHttpHeaders(), bodyBytes, charset, response.rawStatusCode(), response.headers().asHttpHeaders(), bodyBytes, charset,
public DefaultClientResponseBuilder(ClientResponse other) { Assert.notNull(other, "ClientResponse must not be null"); this.strategies = other.strategies(); statusCode(other.statusCode()); headers(headers -> headers.addAll(other.headers().asHttpHeaders())); cookies(cookies -> cookies.addAll(other.cookies())); }
private Function<ClientResponse, Mono<DetectedEndpoint>> convert(EndpointDefinition endpointDefinition, URI uri) { return response -> { Mono<DetectedEndpoint> endpoint = Mono.empty(); if (response.statusCode().is2xxSuccessful()) { endpoint = Mono.just(DetectedEndpoint.of(endpointDefinition, uri.toString())); } return response.bodyToMono(Void.class).then(endpoint); }; }
@Test public void normal() { Flux<DataBuffer> body = Flux.just("baz") .map(s -> s.getBytes(StandardCharsets.UTF_8)) .map(dataBufferFactory::wrap); ClientResponse response = ClientResponse.create(HttpStatus.BAD_GATEWAY, ExchangeStrategies.withDefaults()) .header("foo", "bar") .cookie("baz", "qux") .body(body) .build(); assertEquals(HttpStatus.BAD_GATEWAY, response.statusCode()); HttpHeaders responseHeaders = response.headers().asHttpHeaders(); assertEquals("bar", responseHeaders.getFirst("foo")); assertNotNull("qux", response.cookies().getFirst("baz")); assertEquals("qux", response.cookies().getFirst("baz").getValue()); StepVerifier.create(response.bodyToFlux(String.class)) .expectNext("baz") .verifyComplete(); }
@Override public <T> Mono<T> bodyToMono(ParameterizedTypeReference<T> typeReference) { return this.delegate.bodyToMono(typeReference); }
@Override public HttpStatus statusCode() { return this.delegate.statusCode(); }
@RequestMapping(path = REQUEST_MAPPING_PATH, method = {RequestMethod.GET, RequestMethod.HEAD, RequestMethod.POST, RequestMethod.PUT, RequestMethod.PATCH, RequestMethod.DELETE, RequestMethod.OPTIONS}) public Mono<Void> endpointProxy(@PathVariable("instanceId") String instanceId, ServerHttpRequest request, ServerHttpResponse response) { String endpointLocalPath = getEndpointLocalPath(request.getPath().pathWithinApplication().value()); URI uri = UriComponentsBuilder.fromPath(endpointLocalPath) .query(request.getURI().getRawQuery()) .build(true) .toUri(); return super.forward(instanceId, uri, request.getMethod(), request.getHeaders(), () -> BodyInserters.fromDataBuffers(request.getBody())).flatMap(clientResponse -> { response.setStatusCode(clientResponse.statusCode()); response.getHeaders().addAll(filterHeaders(clientResponse.headers().asHttpHeaders())); return response.writeAndFlushWith(clientResponse.body(BodyExtractors.toDataBuffers()).window(1)); }); } }
private static <T> Mono<T> doDecode(ClientResponse response, Class<T> responseType, String content) { String mediaType = response.headers().contentType().map(MediaType::toString).orElse(XContentType.JSON.mediaType()); try { Method fromXContent = ReflectionUtils.findMethod(responseType, "fromXContent", XContentParser.class); return Mono.justOrEmpty(responseType .cast(ReflectionUtils.invokeMethod(fromXContent, responseType, createParser(mediaType, content)))); } catch (Throwable errorParseFailure) { // cause elasticsearch also uses AssertionError try { return Mono.error(BytesRestResponse.errorFromXContent(createParser(mediaType, content))); } catch (Exception e) { return Mono .error(new ElasticsearchStatusException(content, RestStatus.fromCode(response.statusCode().value()))); } } }
.exchange() .flatMap(response ->{ if (!response.statusCode().is2xxSuccessful()){ throw WebClientResponseException.create(response.rawStatusCode(), "Cannot get token, expected 2xx HTTP Status code", null, ); return response.body(oauth2AccessTokenResponse()); }) .map(response -> { if (response.getAccessToken().getScopes().isEmpty()) {
private static Mono<UserInfoErrorResponse> parse(ClientResponse httpResponse) { String wwwAuth = httpResponse.headers().asHttpHeaders().getFirst(HttpHeaders.WWW_AUTHENTICATE); if (!StringUtils.isEmpty(wwwAuth)) { // Bearer token error? return Mono.fromCallable(() -> UserInfoErrorResponse.parse(wwwAuth)); } ParameterizedTypeReference<Map<String, String>> typeReference = new ParameterizedTypeReference<Map<String, String>>() {}; // Other error? return httpResponse .bodyToMono(typeReference) .map(body -> new UserInfoErrorResponse(ErrorObject.parse(new JSONObject(body)))); } }
@Override public <T> T body(BodyExtractor<T, ? super ClientHttpResponse> extractor) { return this.delegate.body(extractor); }
@Test public void values() { Flux<Msg> result = this.webClient.get() .uri("/messages") .exchange() .doOnNext(response -> { Assert.assertEquals("true", response.headers().contentType().get().getParameters().get("delimited")); Assert.assertEquals("sample.proto", response.headers().header("X-Protobuf-Schema").get(0)); Assert.assertEquals("Msg", response.headers().header("X-Protobuf-Message").get(0)); }) .flatMapMany(response -> response.bodyToFlux(Msg.class)); StepVerifier.create(result) .expectNext(TEST_MSG) .expectNext(TEST_MSG) .expectNext(TEST_MSG) .verifyComplete(); }
private <T> Publisher<? extends T> readResponseBody(String logId, Request request, ClientResponse response, Class<T> responseType) { if (RawActionResponse.class.equals(responseType)) { ClientLogger.logRawResponse(logId, response.statusCode()); return Mono.just(responseType.cast(RawActionResponse.create(response))); } if (response.statusCode().is5xxServerError()) { ClientLogger.logRawResponse(logId, response.statusCode()); return handleServerError(request, response); } return response.body(BodyExtractors.toMono(byte[].class)) // .map(it -> new String(it, StandardCharsets.UTF_8)) // .doOnNext(it -> ClientLogger.logResponse(logId, response.statusCode(), it)) // .flatMap(content -> doDecode(response, responseType, content)); }
@Override public Headers headers() { return this.delegate.headers(); }
private <T extends Publisher<?>> T handleBody(ClientResponse response, T bodyPublisher, Function<Mono<? extends Throwable>, T> errorFunction) { if (HttpStatus.resolve(response.rawStatusCode()) != null) { for (StatusHandler handler : this.statusHandlers) { if (handler.test(response.statusCode())) { HttpRequest request = this.requestSupplier.get(); Mono<? extends Throwable> exMono = handler.apply(response, request); exMono = exMono.flatMap(ex -> drainBody(response, ex)); exMono = exMono.onErrorResume(ex -> drainBody(response, ex)); return errorFunction.apply(exMono); } } return bodyPublisher; } else { return errorFunction.apply(createResponseException(response, this.requestSupplier.get())); } }
private static Function<ClientResponse, Mono<ClientResponse>> convertClientResponse(Function<Flux<DataBuffer>, Flux<DataBuffer>> bodConverter, MediaType contentType) { return response -> { ClientResponse convertedResponse = ClientResponse.from(response).headers(headers -> { headers.replace(HttpHeaders.CONTENT_TYPE, singletonList(contentType.toString())); headers.remove(HttpHeaders.CONTENT_LENGTH); }).body(response.bodyToFlux(DataBuffer.class).transform(bodConverter)).build(); return Mono.just(convertedResponse); }; }
/** * Consume up to the specified number of bytes from the response body and * cancel if any more data arrives. * <p>Internally delegates to {@link DataBufferUtils#takeUntilByteCount}. * @param maxByteCount the limit as number of bytes * @return the filter to limit the response size with * @since 5.1 */ public static ExchangeFilterFunction limitResponseSize(long maxByteCount) { return (request, next) -> next.exchange(request).map(response -> { Flux<DataBuffer> body = response.body(BodyExtractors.toDataBuffers()); body = DataBufferUtils.takeUntilByteCount(body, maxByteCount); return ClientResponse.from(response).body(body).build(); }); }
@Test public void limitResponseSize() { DefaultDataBufferFactory bufferFactory = new DefaultDataBufferFactory(); DataBuffer b1 = dataBuffer("foo", bufferFactory); DataBuffer b2 = dataBuffer("bar", bufferFactory); DataBuffer b3 = dataBuffer("baz", bufferFactory); ClientRequest request = ClientRequest.create(HttpMethod.GET, DEFAULT_URL).build(); ClientResponse response = ClientResponse.create(HttpStatus.OK).body(Flux.just(b1, b2, b3)).build(); Mono<ClientResponse> result = ExchangeFilterFunctions.limitResponseSize(5) .filter(request, req -> Mono.just(response)); StepVerifier.create(result.flatMapMany(res -> res.body(BodyExtractors.toDataBuffers()))) .consumeNextWith(buffer -> assertEquals("foo", string(buffer))) .consumeNextWith(buffer -> assertEquals("ba", string(buffer))) .expectComplete() .verify(); }