spring
RestTemplate
Recherche…
Téléchargement d'un fichier volumineux
Les méthodes getForObject
et getForEntity
de RestTemplate
chargent la totalité de la réponse en mémoire. Cela ne convient pas au téléchargement de fichiers volumineux, car cela peut entraîner des exceptions de mémoire insuffisante. Cet exemple montre comment diffuser la réponse à une requête GET.
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);
Notez que vous ne pouvez pas simplement renvoyer le InputStream
partir de l'extracteur, car la méthode et le flux sous-jacents sont déjà fermés au retour de la méthode d'exécution.
Utilisation de l'authentification de base préemptive avec RestTemplate et HttpClient
L'authentification de base préemptive consiste à envoyer des informations d'authentification de base HTTP (nom d'utilisateur et mot de passe) avant que le serveur ne réponde avec une réponse 401
les demandant. Cela peut sauver un aller-retour de demande lors de la consommation d'API REST, qui nécessitent une authentification de base.
Comme décrit dans la documentation Spring , Apache HttpClient peut être utilisé comme implémentation sous-jacente pour créer des requêtes HTTP à l'aide de HttpComponentsClientHttpRequestFactory
. HttpClient peut être configuré pour effectuer une authentification de base préemptive .
La classe suivante étend HttpComponentsClientHttpRequestFactory
pour fournir une authentification de base préemptive.
/**
* {@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);
}
}
}
Cela peut être utilisé comme suit:
HttpClientBuilder builder = HttpClientBuilder.create();
ClientHttpRequestFactory requestFactory =
new PreAuthHttpComponentsClientHttpRequestFactory(builder.build(),
"api.some-host.com", true, "api", "my-key");
RestTemplate restTemplate = new RestTemplate(requestFactory);
Utilisation de l'authentification de base avec HttpClient de HttpComponent
L'utilisation de HttpClient
comme RestTemplate
sous-jacente de RestTemplate
pour créer des requêtes HTTP permet de gérer automatiquement les requêtes d'authentification de base (une réponse http 401) lors de l'interaction avec les API. Cet exemple montre comment configurer un RestTemplate
pour y parvenir.
// 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);
Définition d'en-têtes sur la demande Spring RestTemplate
Les méthodes d' exchange
de RestTemplate
vous permettent de spécifier une HttpEntity
qui sera écrite dans la requête lors de l'exécution de la méthode. Vous pouvez ajouter des en-têtes (tel agent utilisateur, référent ...) à cette entité:
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());
}
Vous pouvez également ajouter un intercepteur à votre RestTemplate
si vous devez ajouter les mêmes en-têtes à plusieurs requêtes:
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());
}
Résultats génériques de Spring RestTemplate
Pour laisser RestTemplate
comprendre le générique du contenu renvoyé, nous devons définir une référence de type de résultat.
org.springframework.core.ParameterizedTypeReference
a été introduit depuis 3.2
Wrapper<Model> response = restClient.exchange(url,
HttpMethod.GET,
null,
new ParameterizedTypeReference<Wrapper<Model>>() {}).getBody();
Pourrait être utile pour obtenir, par exemple, la List<User>
d'un contrôleur.