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.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow