spring
Plantilla de descanso
Buscar..
Descarga de un archivo grande
Los métodos getForObject
y getForEntity
de RestTemplate
cargan la respuesta completa en la memoria. Esto no es adecuado para descargar archivos grandes, ya que puede causar excepciones de memoria. Este ejemplo muestra cómo transmitir la respuesta de una solicitud 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);
Tenga en cuenta que no puede simplemente devolver el InputStream
desde el extractor, porque en el momento en que el método de ejecución devuelve, la conexión subyacente y la secuencia ya están cerradas.
Uso de la autenticación básica preventiva con RestTemplate y HttpClient
La autenticación básica preventiva es la práctica de enviar las credenciales de autenticación básica de HTTP (nombre de usuario y contraseña) antes de que un servidor responda con una respuesta 401
solicitándolas. Esto puede ahorrar una solicitud de ida y vuelta cuando se consumen apis REST que se sabe que requieren una autenticación básica.
Como se describe en la documentación de Spring , Apache HttpClient puede usarse como la implementación subyacente para crear solicitudes HTTP mediante el uso de HttpComponentsClientHttpRequestFactory
. HttpClient se puede configurar para realizar una autenticación básica preventiva .
La siguiente clase extiende HttpComponentsClientHttpRequestFactory
para proporcionar autenticación básica preferente.
/**
* {@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);
}
}
}
Esto se puede utilizar de la siguiente manera:
HttpClientBuilder builder = HttpClientBuilder.create();
ClientHttpRequestFactory requestFactory =
new PreAuthHttpComponentsClientHttpRequestFactory(builder.build(),
"api.some-host.com", true, "api", "my-key");
RestTemplate restTemplate = new RestTemplate(requestFactory);
Usando la autenticación básica con HttpComponent's HttpClient
El uso de HttpClient
como la implementación subyacente de RestTemplate
para crear solicitudes HTTP permite el manejo automático de las solicitudes de autenticación básicas (una respuesta http 401) cuando se interactúa con las API. Este ejemplo muestra cómo configurar un RestTemplate
para lograr esto.
// 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);
Configuración de encabezados en Spring RestTemplate request
Los métodos de exchange
de RestTemplate
permiten especificar una HttpEntity
que se escribirá en la solicitud cuando se ejecute el método. Puede agregar encabezados (como agente de usuario, referente ...) a esta entidad:
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());
}
También puede agregar un interceptor a su RestTemplate
si necesita agregar los mismos encabezados a múltiples solicitudes:
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());
}
Resultados genéricos de Spring RestTemplate
Para que RestTemplate
comprenda el contenido genérico del contenido devuelto, debemos definir la referencia de tipo de resultado.
org.springframework.core.ParameterizedTypeReference
se ha introducido desde 3.2
Wrapper<Model> response = restClient.exchange(url,
HttpMethod.GET,
null,
new ParameterizedTypeReference<Wrapper<Model>>() {}).getBody();
Podría ser útil para obtener, por ejemplo, la List<User>
de un controlador.