Add `ClientHttpRequestInitializer` support
Add `ClientHttpRequestInitializer` interface that can be used with any `HttpAccessor` to initialize each `ClientHttpRequest` before it's used. This provides a useful alternative to `ClientHttpRequestInterceptor` when users need to configure things like `HttpHeaders`. Closes gh-22002
This commit is contained in:
parent
b587003d8d
commit
5d785390eb
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.http.client;
|
||||
|
||||
import org.springframework.http.client.support.HttpAccessor;
|
||||
|
||||
/**
|
||||
* Callback interface for initializing a {@link ClientHttpRequest} prior to it
|
||||
* being used.
|
||||
*
|
||||
* <p> Typically used with {@link HttpAccessor} and subclasses such as
|
||||
* {@link org.springframework.web.client.RestTemplate RestTemplate} to apply
|
||||
* consistent settings or headers to each request.
|
||||
*
|
||||
* <p>Unlike {@link ClientHttpRequestInterceptor}, this interface can apply
|
||||
* customizations without needing to read the entire request body into memory.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 5.2
|
||||
* @see HttpAccessor#getClientHttpRequestInitializers()
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ClientHttpRequestInitializer {
|
||||
|
||||
/**
|
||||
* Initialize the given client HTTP request.
|
||||
* @param request the request to configure
|
||||
*/
|
||||
void initialize(ClientHttpRequest request);
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -18,13 +18,17 @@ package org.springframework.http.client.support;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.http.HttpLogging;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.ClientHttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpRequestInitializer;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
@ -49,6 +53,8 @@ public abstract class HttpAccessor {
|
|||
|
||||
private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||
|
||||
private List<ClientHttpRequestInitializer> clientHttpRequestInitializers = new ArrayList<>();
|
||||
|
||||
|
||||
/**
|
||||
* Set the request factory that this accessor uses for obtaining client request handles.
|
||||
|
@ -74,6 +80,28 @@ public abstract class HttpAccessor {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the request initializers the this accessor should use.
|
||||
* <p>The initializers will get sorted according to their order
|
||||
* before the {@link ClientHttpRequest} is initialized.
|
||||
*/
|
||||
public void setClientHttpRequestInitializers(
|
||||
List<ClientHttpRequestInitializer> clientHttpRequestInitializers) {
|
||||
if (this.clientHttpRequestInitializers != clientHttpRequestInitializers) {
|
||||
this.clientHttpRequestInitializers.clear();
|
||||
this.clientHttpRequestInitializers.addAll(clientHttpRequestInitializers);
|
||||
AnnotationAwareOrderComparator.sort(this.clientHttpRequestInitializers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the request initializers that this accessor uses.
|
||||
* <p>The returned {@link List} is active and may get appended to.
|
||||
*/
|
||||
public List<ClientHttpRequestInitializer> getClientHttpRequestInitializers() {
|
||||
return this.clientHttpRequestInitializers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ClientHttpRequest} via this template's {@link ClientHttpRequestFactory}.
|
||||
* @param url the URL to connect to
|
||||
|
@ -85,10 +113,16 @@ public abstract class HttpAccessor {
|
|||
*/
|
||||
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
|
||||
ClientHttpRequest request = getRequestFactory().createRequest(url, method);
|
||||
initialize(request);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("HTTP " + method.name() + " " + url);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
private void initialize(ClientHttpRequest request) {
|
||||
this.clientHttpRequestInitializers.forEach(
|
||||
initializer -> initializer.initialize(request));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.springframework.http.MediaType;
|
|||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.ClientHttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpRequestInitializer;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
|
@ -679,6 +680,32 @@ public class RestTemplateTests {
|
|||
verify(response).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clientHttpRequestInitializerAndRequestInterceptorAreBothApplied() throws Exception {
|
||||
ClientHttpRequestInitializer initializer = request ->
|
||||
request.getHeaders().add("MyHeader", "MyInitializerValue");
|
||||
ClientHttpRequestInterceptor interceptor = (request, body, execution) -> {
|
||||
request.getHeaders().add("MyHeader", "MyInterceptorValue");
|
||||
return execution.execute(request, body);
|
||||
};
|
||||
template.setClientHttpRequestInitializers(Collections.singletonList(initializer));
|
||||
template.setInterceptors(Collections.singletonList(interceptor));
|
||||
|
||||
MediaType contentType = MediaType.TEXT_PLAIN;
|
||||
given(converter.canWrite(String.class, contentType)).willReturn(true);
|
||||
HttpHeaders requestHeaders = new HttpHeaders();
|
||||
mockSentRequest(POST, "https://example.com", requestHeaders);
|
||||
mockResponseStatus(HttpStatus.OK);
|
||||
|
||||
HttpHeaders entityHeaders = new HttpHeaders();
|
||||
entityHeaders.setContentType(contentType);
|
||||
HttpEntity<String> entity = new HttpEntity<>("Hello World", entityHeaders);
|
||||
template.exchange("https://example.com", POST, entity, Void.class);
|
||||
assertThat(requestHeaders.get("MyHeader")).contains("MyInterceptorValue", "MyInitializerValue");
|
||||
|
||||
verify(response).close();
|
||||
}
|
||||
|
||||
private void mockSentRequest(HttpMethod method, String uri) throws Exception {
|
||||
mockSentRequest(method, uri, new HttpHeaders());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue