下面列出了怎么用org.springframework.http.client.reactive.ClientHttpConnector的API类实例代码及写法,或者点击链接到github查看源代码。
@Test
public void captureAndClaim() {
ClientHttpRequest request = new MockClientHttpRequest(HttpMethod.GET, "/test");
ClientHttpResponse response = new MockClientHttpResponse(HttpStatus.OK);
ClientHttpConnector connector = (method, uri, fn) -> fn.apply(request).then(Mono.just(response));
ClientRequest clientRequest = ClientRequest.create(HttpMethod.GET, URI.create("/test"))
.header(WebTestClient.WEBTESTCLIENT_REQUEST_ID, "1").build();
WiretapConnector wiretapConnector = new WiretapConnector(connector);
ExchangeFunction function = ExchangeFunctions.create(wiretapConnector);
function.exchange(clientRequest).block(ofMillis(0));
WiretapConnector.Info actual = wiretapConnector.claimRequest("1");
ExchangeResult result = actual.createExchangeResult(Duration.ZERO, null);
assertEquals(HttpMethod.GET, result.getMethod());
assertEquals("/test", result.getUrl().toString());
}
@Test
public void captureAndClaim() {
ClientHttpRequest request = new MockClientHttpRequest(HttpMethod.GET, "/test");
ClientHttpResponse response = new MockClientHttpResponse(HttpStatus.OK);
ClientHttpConnector connector = (method, uri, fn) -> fn.apply(request).then(Mono.just(response));
ClientRequest clientRequest = ClientRequest.create(HttpMethod.GET, URI.create("/test"))
.header(WebTestClient.WEBTESTCLIENT_REQUEST_ID, "1").build();
WiretapConnector wiretapConnector = new WiretapConnector(connector);
ExchangeFunction function = ExchangeFunctions.create(wiretapConnector);
function.exchange(clientRequest).block(ofMillis(0));
WiretapConnector.Info actual = wiretapConnector.claimRequest("1");
ExchangeResult result = actual.createExchangeResult(Duration.ZERO, null);
assertEquals(HttpMethod.GET, result.getMethod());
assertEquals("/test", result.getUrl().toString());
}
/**
* Create a {@link ClientHttpConnector} for the given {@link ClientOptions} and
* {@link SslConfiguration}.
* @param options must not be {@literal null}
* @param sslConfiguration must not be {@literal null}
* @return a new {@link ClientHttpConnector}.
*/
public static ClientHttpConnector create(ClientOptions options, SslConfiguration sslConfiguration) {
Assert.notNull(options, "ClientOptions must not be null");
Assert.notNull(sslConfiguration, "SslConfiguration must not be null");
if (REACTOR_NETTY_PRESENT) {
return ReactorNetty.usingReactorNetty(options, sslConfiguration);
}
if (JETTY_PRESENT) {
return JettyClient.usingJetty(options, sslConfiguration);
}
throw new IllegalStateException("No supported Reactive Http Client library available (Reactor Netty, Jetty)");
}
static ClientHttpConnector usingReactorNetty(ClientOptions options, SslConfiguration sslConfiguration) {
HttpClient client = HttpClient.create();
if (hasSslConfiguration(sslConfiguration)) {
SslContextBuilder sslContextBuilder = SslContextBuilder.forClient();
configureSsl(sslConfiguration, sslContextBuilder);
client = client.secure(builder -> {
builder.sslContext(sslContextBuilder);
});
}
client = client.tcpConfiguration(it -> it.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,
Math.toIntExact(options.getConnectionTimeout().toMillis())));
return new ReactorClientHttpConnector(client);
}
@Test
void justLoginRequestShouldLogin() {
ClientHttpRequest request = new MockClientHttpRequest(HttpMethod.POST, "/auth/cert/login");
MockClientHttpResponse response = new MockClientHttpResponse(HttpStatus.OK);
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
response.setBody(
"{" + "\"auth\":{\"client_token\":\"my-token\", \"renewable\": true, \"lease_duration\": 10}" + "}");
ClientHttpConnector connector = (method, uri, fn) -> fn.apply(request).then(Mono.just(response));
WebClient webClient = WebClient.builder().clientConnector(connector).build();
AuthenticationSteps steps = AuthenticationSteps
.just(post("/auth/{path}/login", "cert").as(VaultResponse.class));
login(steps, webClient).as(StepVerifier::create) //
.expectNext(VaultToken.of("my-token")) //
.verifyComplete();
}
@Test
void justLoginShouldFail() {
ClientHttpRequest request = new MockClientHttpRequest(HttpMethod.POST, "/auth/cert/login");
MockClientHttpResponse response = new MockClientHttpResponse(HttpStatus.BAD_REQUEST);
ClientHttpConnector connector = (method, uri, fn) -> fn.apply(request).then(Mono.just(response));
WebClient webClient = WebClient.builder().clientConnector(connector).build();
AuthenticationSteps steps = AuthenticationSteps
.just(post("/auth/{path}/login", "cert").as(VaultResponse.class));
login(steps, webClient).as(StepVerifier::create) //
.expectError() //
.verify();
}
@Test
void shouldApplyNamespace() {
ClientHttpRequest request = new MockClientHttpRequest(HttpMethod.POST, "/auth/foo");
MockClientHttpResponse response = new MockClientHttpResponse(HttpStatus.OK);
ClientHttpConnector connector = (method, uri, fn) -> fn.apply(request).then(Mono.just(response));
WebClient webClient = WebClient.builder().clientConnector(connector)
.filter(ReactiveVaultClients.namespace("foo/bar")).build();
webClient.get().uri("/auth/foo").retrieve().bodyToMono(String.class).as(StepVerifier::create) //
.verifyComplete();
assertThat(request.getHeaders()).containsEntry(VaultHttpHeaders.VAULT_NAMESPACE,
Collections.singletonList("foo/bar"));
}
@Test
void shouldAllowNamespaceOverride() {
ClientHttpRequest request = new MockClientHttpRequest(HttpMethod.POST, "/auth/foo");
MockClientHttpResponse response = new MockClientHttpResponse(HttpStatus.OK);
ClientHttpConnector connector = (method, uri, fn) -> fn.apply(request).then(Mono.just(response));
WebClient webClient = WebClient.builder().clientConnector(connector)
.filter(ReactiveVaultClients.namespace("foo/bar")).build();
webClient.get().uri("/auth/foo").header(VaultHttpHeaders.VAULT_NAMESPACE, "baz").retrieve()
.bodyToMono(String.class) //
.as(StepVerifier::create) //
.verifyComplete();
assertThat(request.getHeaders()).containsEntry(VaultHttpHeaders.VAULT_NAMESPACE,
Collections.singletonList("baz"));
}
@Test
public void givenReactiveClient_whenRequested_shouldReturnResponse() throws Exception {
HttpClient httpClient = new HttpClient();
httpClient.start();
ClientHttpConnector clientConnector = new JettyClientHttpConnector(httpClient);
WebClient client = WebClient.builder()
.clientConnector(clientConnector)
.build();
String responseContent = client.post()
.uri(uri())
.contentType(MediaType.TEXT_PLAIN)
.body(BodyInserters.fromPublisher(Mono.just(CONTENT), String.class))
.retrieve()
.bodyToMono(String.class)
.block();
Assert.assertNotNull(responseContent);
Assert.assertEquals(CONTENT, responseContent);
}
public DefaultExchangeFunction(ClientHttpConnector connector, ExchangeStrategies strategies) {
Assert.notNull(connector, "ClientHttpConnector must not be null");
Assert.notNull(strategies, "ExchangeStrategies must not be null");
this.connector = connector;
this.strategies = strategies;
strategies.messageWriters().stream()
.filter(LoggingCodecSupport.class::isInstance)
.forEach(reader -> {
if (((LoggingCodecSupport) reader).isEnableLoggingRequestDetails()) {
this.enableLoggingRequestDetails = true;
}
});
}
private DefaultWebTestClientBuilder(@Nullable WebClient.Builder webClientBuilder,
@Nullable WebHttpHandlerBuilder httpHandlerBuilder, @Nullable ClientHttpConnector connector,
@Nullable Duration responseTimeout) {
Assert.isTrue(httpHandlerBuilder != null || connector != null,
"Either WebHttpHandlerBuilder or ClientHttpConnector must be provided");
this.webClientBuilder = (webClientBuilder != null ? webClientBuilder : WebClient.builder());
this.httpHandlerBuilder = (httpHandlerBuilder != null ? httpHandlerBuilder.clone() : null);
this.connector = connector;
this.responseTimeout = responseTimeout;
}
@Override
public WebTestClient build() {
ClientHttpConnector connectorToUse = this.connector;
if (connectorToUse == null) {
Assert.state(this.httpHandlerBuilder != null, "No WebHttpHandlerBuilder available");
connectorToUse = new HttpHandlerConnector(this.httpHandlerBuilder.build());
}
return new DefaultWebTestClient(this.webClientBuilder,
connectorToUse, this.responseTimeout, new DefaultWebTestClientBuilder(this));
}
DefaultWebTestClient(WebClient.Builder clientBuilder, ClientHttpConnector connector,
@Nullable Duration timeout, DefaultWebTestClientBuilder webTestClientBuilder) {
Assert.notNull(clientBuilder, "WebClient.Builder is required");
this.wiretapConnector = new WiretapConnector(connector);
this.webClient = clientBuilder.clientConnector(this.wiretapConnector).build();
this.timeout = (timeout != null ? timeout : Duration.ofSeconds(5));
this.builder = webTestClientBuilder;
}
@Override
public void afterConfigurerAdded(WebTestClient.Builder builder,
@Nullable WebHttpHandlerBuilder httpHandlerBuilder,
@Nullable ClientHttpConnector connector) {
Assert.notNull(httpHandlerBuilder, "Not a mock server");
httpHandlerBuilder.filters(filters -> {
filters.removeIf(filter -> filter instanceof IdentityFilter);
filters.add(0, this.filter);
});
}
public DefaultExchangeFunction(ClientHttpConnector connector, ExchangeStrategies strategies) {
Assert.notNull(connector, "ClientHttpConnector must not be null");
Assert.notNull(strategies, "ExchangeStrategies must not be null");
this.connector = connector;
this.strategies = strategies;
strategies.messageWriters().stream()
.filter(LoggingCodecSupport.class::isInstance)
.forEach(reader -> {
if (((LoggingCodecSupport) reader).isEnableLoggingRequestDetails()) {
this.enableLoggingRequestDetails = true;
}
});
}
private DefaultWebTestClientBuilder(@Nullable WebClient.Builder webClientBuilder,
@Nullable WebHttpHandlerBuilder httpHandlerBuilder, @Nullable ClientHttpConnector connector,
@Nullable Duration responseTimeout) {
Assert.isTrue(httpHandlerBuilder != null || connector != null,
"Either WebHttpHandlerBuilder or ClientHttpConnector must be provided");
this.webClientBuilder = (webClientBuilder != null ? webClientBuilder : WebClient.builder());
this.httpHandlerBuilder = (httpHandlerBuilder != null ? httpHandlerBuilder.clone() : null);
this.connector = connector;
this.responseTimeout = responseTimeout;
}
@Override
public WebTestClient build() {
ClientHttpConnector connectorToUse = this.connector;
if (connectorToUse == null) {
Assert.state(this.httpHandlerBuilder != null, "No WebHttpHandlerBuilder available");
connectorToUse = new HttpHandlerConnector(this.httpHandlerBuilder.build());
}
return new DefaultWebTestClient(this.webClientBuilder,
connectorToUse, this.responseTimeout, new DefaultWebTestClientBuilder(this));
}
DefaultWebTestClient(WebClient.Builder clientBuilder, ClientHttpConnector connector,
@Nullable Duration timeout, DefaultWebTestClientBuilder webTestClientBuilder) {
Assert.notNull(clientBuilder, "WebClient.Builder is required");
this.wiretapConnector = new WiretapConnector(connector);
this.webClient = clientBuilder.clientConnector(this.wiretapConnector).build();
this.timeout = (timeout != null ? timeout : Duration.ofSeconds(5));
this.builder = webTestClientBuilder;
}
@Override
public void afterConfigurerAdded(WebTestClient.Builder builder,
@Nullable WebHttpHandlerBuilder httpHandlerBuilder,
@Nullable ClientHttpConnector connector) {
Assert.notNull(httpHandlerBuilder, "Not a mock server");
httpHandlerBuilder.filters(filters -> {
filters.removeIf(filter -> filter instanceof IdentityFilter);
filters.add(0, this.filter);
});
}
@Test
public void webClientConnectorNotConfigured() {
this.context.withClassLoader(new FilteredClassLoader(WebClient.class))
.withPropertyValues("spring.credhub.url=https://localhost",
"spring.credhub.oauth2.registration-id=test-client", "spring.credhub.connection-timeout=30",
"spring.credhub.read-timeout=60")
.run((context) -> assertThat(context).doesNotHaveBean(ClientHttpConnector.class));
}
/**
* Create a {@link ClientHttpConnector} for the given {@link ClientOptions}.
* @param options must not be {@literal null}
* @return a new {@link ClientHttpConnector}.
*/
public static ClientHttpConnector create(ClientOptions options) {
HttpClient httpClient = HttpClient.create();
if (usingCustomCerts(options)) {
TrustManagerFactory trustManagerFactory = sslCertificateUtils
.createTrustManagerFactory(options.getCaCertFiles());
httpClient = httpClient.secure((sslContextSpec) -> sslContextSpec.sslContext(
SslContextBuilder.forClient().sslProvider(SslProvider.JDK).trustManager(trustManagerFactory)));
}
else {
httpClient = httpClient.secure((sslContextSpec) -> {
try {
sslContextSpec.sslContext(new JdkSslContext(SSLContext.getDefault(), true, null,
IdentityCipherSuiteFilter.INSTANCE, null, ClientAuth.REQUIRE, null, false));
}
catch (NoSuchAlgorithmException ex) {
logger.error("Error configuring HTTP connections", ex);
throw new RuntimeException("Error configuring HTTP connections", ex);
}
});
}
if (options.getConnectionTimeout() != null) {
httpClient = httpClient
.tcpConfiguration((tcpClient) -> tcpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,
Math.toIntExact(options.getConnectionTimeout().toMillis())));
}
return new ReactorClientHttpConnector(httpClient);
}
/**
* Create a new {@link ReactiveCredHubTemplate} using the provided base URI and
* {@link ClientHttpRequestFactory}.
* @param credHubProperties connection properties for the CredHub server
* @param clientHttpConnector the {@link ClientHttpConnector} to use when creating new
* connections
*/
public ReactiveCredHubTemplate(CredHubProperties credHubProperties, ClientHttpConnector clientHttpConnector) {
Assert.notNull(credHubProperties, "credHubProperties must not be null");
Assert.notNull(clientHttpConnector, "clientHttpConnector must not be null");
this.webClient = CredHubWebClientFactory.createWebClient(credHubProperties, clientHttpConnector);
this.usingOAuth2 = false;
}
/**
* Create a new {@link ReactiveCredHubTemplate} using the provided base URI and
* {@link ClientHttpRequestFactory}.
* @param credHubProperties connection properties for the CredHub server
* @param clientHttpConnector the {@link ClientHttpConnector} to use when creating new
* connections
* @param clientRegistrationRepository a repository of OAuth2 client registrations
* @param authorizedClientRepository a repository of authorized OAuth2 clients
*/
public ReactiveCredHubTemplate(CredHubProperties credHubProperties, ClientHttpConnector clientHttpConnector,
ReactiveClientRegistrationRepository clientRegistrationRepository,
ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
Assert.notNull(credHubProperties, "credHubProperties must not be null");
Assert.notNull(clientHttpConnector, "clientHttpConnector must not be null");
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository must not be null");
Assert.notNull(authorizedClientRepository, "authorizedClientRepository must not be null");
this.webClient = CredHubWebClientFactory.createWebClient(credHubProperties, clientHttpConnector,
clientRegistrationRepository, authorizedClientRepository);
this.usingOAuth2 = true;
}
/**
* Create a new {@link ReactiveCredHubTemplate} using the provided base URI and
* {@link ClientHttpRequestFactory}.
* @param credHubProperties connection properties for the CredHub server
* @param clientHttpConnector the {@link ClientHttpConnector} to use when creating new
* connections
* @param clientManager an OAuth2 authorization client manager
*/
public ReactiveCredHubTemplate(CredHubProperties credHubProperties, ClientHttpConnector clientHttpConnector,
ReactiveOAuth2AuthorizedClientManager clientManager) {
Assert.notNull(credHubProperties, "credHubProperties must not be null");
Assert.notNull(clientHttpConnector, "clientHttpConnector must not be null");
Assert.notNull(clientManager, "clientManager must not be null");
this.webClient = CredHubWebClientFactory.createWebClient(credHubProperties, clientHttpConnector, clientManager);
this.usingOAuth2 = true;
}
/**
* Create a {@link WebClient} configured for communication with a CredHub server.
* @param properties the CredHub connection properties
* @param clientHttpConnector the {@link ClientHttpConnector} to use when creating new
* connections
* @param clientRegistrationRepository a repository of OAuth2 client registrations
* @param authorizedClientRepository a repository of OAuth2 authorized clients
* @return a configured {@link WebClient}
*/
static WebClient createWebClient(CredHubProperties properties, ClientHttpConnector clientHttpConnector,
ReactiveClientRegistrationRepository clientRegistrationRepository,
ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
ReactiveOAuth2AuthorizedClientProvider clientProvider = buildClientProvider(clientHttpConnector);
DefaultReactiveOAuth2AuthorizedClientManager defaultClientManager = buildClientManager(
clientRegistrationRepository, authorizedClientRepository, clientProvider);
return createWebClient(properties, clientHttpConnector, defaultClientManager);
}
/**
* Create a {@link WebClient} configured for communication with a CredHub server.
* @param properties the CredHub connection properties
* @param clientHttpConnector the {@link ClientHttpConnector} to use when creating new
* connections
* @param clientManager an OAuth2 client manager to use to authenticate a client
* @return a configured {@link WebClient}
*/
static WebClient createWebClient(CredHubProperties properties, ClientHttpConnector clientHttpConnector,
ReactiveOAuth2AuthorizedClientManager clientManager) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
clientManager);
return buildWebClient(properties.getUrl(), clientHttpConnector).filter(oauth).defaultRequest(
(requestHeadersSpec) -> requestHeadersSpec.attributes(ServerOAuth2AuthorizedClientExchangeFilterFunction
.clientRegistrationId(properties.getOauth2().getRegistrationId())))
.build();
}
private static WebClient.Builder buildWebClient(String baseUri, ClientHttpConnector clientHttpConnector) {
ExchangeStrategies strategies = ExchangeStrategies.builder().codecs((configurer) -> {
ObjectMapper mapper = JsonUtils.buildObjectMapper();
CodecConfigurer.DefaultCodecs dc = configurer.defaultCodecs();
dc.jackson2JsonDecoder(new Jackson2JsonDecoder(mapper));
dc.jackson2JsonEncoder(new Jackson2JsonEncoder(mapper));
}).build();
return WebClient.builder().clientConnector(clientHttpConnector).baseUrl(baseUri)
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.exchangeStrategies(strategies);
}
/**
* Set the {@link Supplier} of {@link ClientHttpConnector} that should be called each
* time we {@link #build()} a new {@link WebClient} instance.
* @param httpConnector the supplier for the HTTP connector.
* @return {@code this} {@link WebClientBuilder}.
* @since 2.2.1
*/
public WebClientBuilder httpConnectorFactory(Supplier<ClientHttpConnector> httpConnector) {
Assert.notNull(httpConnector, "Supplier of ClientHttpConnector must not be null");
this.httpConnector = httpConnector;
return this;
}
static ClientHttpConnector usingJetty(ClientOptions options, SslConfiguration sslConfiguration) {
try {
return new JettyClientHttpConnector(configureClient(getHttpClient(sslConfiguration), options));
}
catch (GeneralSecurityException | IOException e) {
throw new IllegalStateException(e);
}
}
/**
* Create a {@link WebClientFactory} bean that is used to produce a {@link WebClient}.
* @return the {@link WebClientFactory}.
* @see #clientHttpConnector()
* @since 2.3
*/
@Bean
public WebClientFactory webClientFactory() {
ClientHttpConnector httpConnector = clientHttpConnector();
return new DefaultWebClientFactory(httpConnector, clientHttpConnector -> {
return webClientBuilder(reactiveVaultEndpointProvider(), clientHttpConnector);
});
}