spring
RestTemplate
Ricerca…
Download di un file di grandi dimensioni
I metodi getForObject
e getForEntity
di RestTemplate
caricano l'intera risposta in memoria. Questo non è adatto per il download di file di grandi dimensioni in quanto può causare eccezioni di memoria insufficiente. Questo esempio mostra come eseguire lo streaming della risposta di una richiesta 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);
Si noti che non è possibile semplicemente restituire InputStream
dall'estrattore, poiché nel momento in cui viene restituito il metodo execute, la connessione e il flusso sottostanti sono già chiusi.
Utilizzo dell'autenticazione di base preventiva con RestTemplate e HttpClient
L'autenticazione di base preventiva è la pratica dell'invio di credenziali di autenticazione di base http (nome utente e password) prima che un server risponda con una risposta 401
richiede. Questo può salvare una richiesta di andata e ritorno quando si utilizzano apis REST che sono noti per richiedere l'autenticazione di base.
Come descritto nella documentazione Spring , Apache HttpClient può essere utilizzato come implementazione sottostante per creare richieste HTTP utilizzando HttpComponentsClientHttpRequestFactory
. HttpClient può essere configurato per eseguire l'autenticazione di base preventiva .
La seguente classe estende HttpComponentsClientHttpRequestFactory
per fornire l'autenticazione di base preventiva.
/**
* {@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);
}
}
}
Questo può essere usato come segue:
HttpClientBuilder builder = HttpClientBuilder.create();
ClientHttpRequestFactory requestFactory =
new PreAuthHttpComponentsClientHttpRequestFactory(builder.build(),
"api.some-host.com", true, "api", "my-key");
RestTemplate restTemplate = new RestTemplate(requestFactory);
Utilizzo dell'autenticazione di base con HttpConent di HttpComponent
L'utilizzo di HttpClient
come implementazione sottostante di RestTemplate
per creare richieste HTTP consente la gestione automatica delle richieste di autenticazione di base (una risposta http 401) quando si interagisce con le API. Questo esempio mostra come configurare un RestTemplate
per ottenere ciò.
// 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);
Impostazione delle intestazioni sulla richiesta Spring RestTemplate
I metodi di exchange
di RestTemplate
consentono di specificare un HttpEntity
che verrà scritto nella richiesta quando si esegue il metodo. È possibile aggiungere intestazioni (agente utente, referente ...) a questa 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());
}
Inoltre, puoi aggiungere un interceptor al tuo RestTemplate
se devi aggiungere le stesse intestazioni a più richieste:
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());
}
Risultati generici da Spring RestTemplate
Per consentire a RestTemplate
comprendere il contenuto restituito generico, è necessario definire il riferimento al tipo di risultato.
org.springframework.core.ParameterizedTypeReference
è stato introdotto dal 3.2
Wrapper<Model> response = restClient.exchange(url,
HttpMethod.GET,
null,
new ParameterizedTypeReference<Wrapper<Model>>() {}).getBody();
Potrebbe essere utile ottenere ad esempio List<User>
da un controller.