spring
RestTemplate
Zoeken…
Een groot bestand downloaden
De methoden getForObject
en getForEntity
van RestTemplate
laden het volledige antwoord in het geheugen. Dit is niet geschikt voor het downloaden van grote bestanden, omdat dit geheugenuitzonderingen kan veroorzaken. Dit voorbeeld laat zien hoe het antwoord van een GET-verzoek kan worden gestreamd.
RestTemplate restTemplate // = ...;
// Optional Accept header
RequestCallback requestCallback = request -> request.getHeaders()
.setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
// Streams the response instead of loading it all in memory
ResponseExtractor<Void> responseExtractor = response -> {
// Here I write the response to a file but do what you like
Path path = Paths.get("some/path");
Files.copy(response.getBody(), path);
return null;
};
restTemplate.execute(URI.create("www.something.com"), HttpMethod.GET, requestCallback, responseExtractor);
Merk op dat u de InputStream
niet eenvoudig kunt retourneren vanuit de extractor, omdat tegen de tijd dat de uitvoeringsmethode terugkeert, de onderliggende verbinding en stream al zijn gesloten.
Preemptive Basic Authentication gebruiken met RestTemplate en HttpClient
Preemptive basic authentication is de gewoonte om http-basisverificatiegegevens (gebruikersnaam en wachtwoord) te verzenden voordat een server antwoordt met een 401
antwoord en erom vraagt. Dit kan een rondreis met verzoek opslaan wanneer REST-apis wordt gebruikt waarvan bekend is dat deze basisverificatie vereisen.
Zoals beschreven in de Spring-documentatie , kan Apache HttpClient worden gebruikt als de onderliggende implementatie om HTTP-aanvragen te maken met behulp van de HttpComponentsClientHttpRequestFactory
. HttpClient kan worden geconfigureerd om preventieve basisverificatie uit te voeren .
De volgende klasse breidt HttpComponentsClientHttpRequestFactory
met preventieve basisverificatie.
/**
* {@link HttpComponentsClientHttpRequestFactory} with preemptive basic
* authentication to avoid the unnecessary first 401 response asking for
* credentials.
* <p>
* Only preemptively sends the given credentials to the given host and
* optionally to its subdomains. Matching subdomains can be useful for APIs
* using multiple subdomains which are not always known in advance.
* <p>
* Other configurations of the {@link HttpClient} are not modified (e.g. the
* default credentials provider).
*/
public class PreAuthHttpComponentsClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory {
private String hostName;
private boolean matchSubDomains;
private Credentials credentials;
/**
* @param httpClient
* client
* @param hostName
* host name
* @param matchSubDomains
* whether to match the host's subdomains
* @param userName
* basic authentication user name
* @param password
* basic authentication password
*/
public PreAuthHttpComponentsClientHttpRequestFactory(HttpClient httpClient, String hostName,
boolean matchSubDomains, String userName, String password) {
super(httpClient);
this.hostName = hostName;
this.matchSubDomains = matchSubDomains;
credentials = new UsernamePasswordCredentials(userName, password);
}
@Override
protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
// Add AuthCache to the execution context
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(new PreAuthCredentialsProvider());
context.setAuthCache(new PreAuthAuthCache());
return context;
}
/**
* @param host
* host name
* @return whether the configured credentials should be used for the given
* host
*/
protected boolean hostNameMatches(String host) {
return host.equals(hostName) || (matchSubDomains && host.endsWith("." + hostName));
}
private class PreAuthCredentialsProvider extends BasicCredentialsProvider {
@Override
public Credentials getCredentials(AuthScope authscope) {
if (hostNameMatches(authscope.getHost())) {
// Simulate a basic authenticationcredentials entry in the
// credentials provider.
return credentials;
}
return super.getCredentials(authscope);
}
}
private class PreAuthAuthCache extends BasicAuthCache {
@Override
public AuthScheme get(HttpHost host) {
if (hostNameMatches(host.getHostName())) {
// Simulate a cache entry for this host. This instructs
// HttpClient to use basic authentication for this host.
return new BasicScheme();
}
return super.get(host);
}
}
}
Dit kan als volgt worden gebruikt:
HttpClientBuilder builder = HttpClientBuilder.create();
ClientHttpRequestFactory requestFactory =
new PreAuthHttpComponentsClientHttpRequestFactory(builder.build(),
"api.some-host.com", true, "api", "my-key");
RestTemplate restTemplate = new RestTemplate(requestFactory);
Basisverificatie gebruiken met HttpComponent's HttpClient
Het gebruik van HttpClient
als de onderliggende implementatie van RestTemplate
om HTTP-aanvragen te maken, zorgt voor automatische afhandeling van basisverificatieaanvragen (een http 401-antwoord) bij interactie met API's. Dit voorbeeld laat zien hoe u een RestTemplate
configureert om dit te bereiken.
// The credentials are stored here
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
// AuthScope can be configured more extensively to restrict
// for which host/port/scheme/etc the credentials will be used.
new AuthScope("somehost", AuthScope.ANY_PORT),
new UsernamePasswordCredentials("username", "password"));
// Use the credentials provider
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setDefaultCredentialsProvider(credsProvider);
// Configure the RestTemplate to use HttpComponent's HttpClient
ClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory(builder.build());
RestTemplate restTemplate = new RestTemplate(requestFactory);
Headers instellen op verzoek van Spring RestTemplate
Met de exchange
van RestTemplate
kunt u een HttpEntity
opgeven die naar het verzoek wordt geschreven wanneer de methode wordt uitgevoerd. U kunt headers (zoals user agent, referrer ...) toevoegen aan deze entiteit:
public void testHeader(final RestTemplate restTemplate){
//Set the headers you need send
final HttpHeaders headers = new HttpHeaders();
headers.set("User-Agent", "eltabo");
//Create a new HttpEntity
final HttpEntity<String> entity = new HttpEntity<String>(headers);
//Execute the method writing your HttpEntity to the request
ResponseEntity<Map> response = restTemplate.exchange("https://httpbin.org/user-agent", HttpMethod.GET, entity, Map.class);
System.out.println(response.getBody());
}
U kunt ook een interceptor aan uw RestTemplate
als u dezelfde headers aan meerdere verzoeken moet toevoegen:
public void testHeader2(final RestTemplate restTemplate){
//Add a ClientHttpRequestInterceptor to the RestTemplate
restTemplate.getInterceptors().add(new ClientHttpRequestInterceptor(){
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
request.getHeaders().set("User-Agent", "eltabo");//Set the header for each request
return execution.execute(request, body);
}
});
ResponseEntity<Map> response = restTemplate.getForEntity("https://httpbin.org/user-agent", Map.class);
System.out.println(response.getBody());
ResponseEntity<Map> response2 = restTemplate.getForEntity("https://httpbin.org/headers", Map.class);
System.out.println(response2.getBody());
}
Generieke resultaten van Spring RestTemplate
Om RestTemplate
generieke of geretourneerde inhoud te laten begrijpen, moeten we de verwijzing naar het resultaattype definiëren.
org.springframework.core.ParameterizedTypeReference
is geïntroduceerd sinds 3.2
Wrapper<Model> response = restClient.exchange(url,
HttpMethod.GET,
null,
new ParameterizedTypeReference<Wrapper<Model>>() {}).getBody();
Zou handig kunnen zijn om bijvoorbeeld List<User>
van een controller te krijgen.