¿Cómo establecer un encabezado "Aceptar:" en la solicitud Spring RestTemplate?

193

Quiero establecer el valor de Accept:en una solicitud que estoy haciendo usando Spring's RestTemplate.

Aquí está mi código de manejo de solicitud de Spring

@RequestMapping(
    value= "/uom_matrix_save_or_edit", 
    method = RequestMethod.POST,
    produces="application/json"
)
public @ResponseBody ModelMap uomMatrixSaveOrEdit(
    ModelMap model,
    @RequestParam("parentId") String parentId
){
    model.addAttribute("attributeValues",parentId);
    return model;
}

y aquí está mi cliente Java REST:

public void post(){
    MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
    params.add("parentId", "parentId");
    String result = rest.postForObject( url, params, String.class) ;
    System.out.println(result);
}

Esto funciona para mi; Me sale una cadena JSON del lado del servidor.

Mi pregunta es: ¿cómo puedo especificar la Accept:cabecera (por ejemplo application/json, application/xml, ...) y el método de la petición (por ejemplo GET, POST, ...) cuando uso RestTemplate?

edaklij
fuente

Respuestas:

353

Sugiero usar uno de los exchangemétodos que acepte uno HttpEntitypara el que también puede configurar HttpHeaders. (También puede especificar el método HTTP que desea usar).

Por ejemplo,

RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

HttpEntity<String> entity = new HttpEntity<>("body", headers);

restTemplate.exchange(url, HttpMethod.POST, entity, String.class);

Prefiero esta solución porque está fuertemente tipada, es decir. exchangeespera un HttpEntity.

Sin embargo, también puede pasar eso HttpEntitycomo un requestargumento para postForObject.

HttpEntity<String> entity = new HttpEntity<>("body", headers);
restTemplate.postForObject(url, entity, String.class); 

Esto se menciona en el RestTemplate#postForObjectJavadoc .

El requestparámetro puede ser un HttpEntitypara agregar encabezados HTTP adicionales a la solicitud .

Sotirios Delimanolis
fuente
130

Puede configurar un interceptor "ClientHttpRequestInterceptor" en su RestTemplate para evitar establecer el encabezado cada vez que envíe una solicitud.

public class HeaderRequestInterceptor implements ClientHttpRequestInterceptor {

        private final String headerName;

        private final String headerValue;

        public HeaderRequestInterceptor(String headerName, String headerValue) {
            this.headerName = headerName;
            this.headerValue = headerValue;
        }

        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
            request.getHeaders().set(headerName, headerValue);
            return execution.execute(request, body);
        }
    }

Luego

List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>();
interceptors.add(new HeaderRequestInterceptor("Accept", MediaType.APPLICATION_JSON_VALUE));

RestTemplate restTemplate = new RestTemplate();
restTemplate.setInterceptors(interceptors);
Ammar
fuente
Spring Boot 1.3 tiene un HttpHeaderInterceptor, por lo que no necesitamos crear nuestra propia implementación de ClientHttpRequestInterceptor.
whistling_marmot
2
Por alguna razón, HttpHeaderInterceptor solo está en spring-boot-devtools. Entonces todavía tenemos que implementar ClientHttpRequestInterceptor nosotros mismos. Creo que debería trasladarse a spring-web.
whistling_marmot
2
¿Es mejor agregar encabezados predeterminados al conjunto ClientHttpRequestFactory a la plantilla de descanso en lugar de agregar interceptores? PD: debe agregar su respuesta en una pregunta separada, ya que se trata de encabezados predeterminados. ¡Tuve que buscar un rato para llegar aquí!
sbsatter
Si hay dos servicios que usan dos ID / Pasos de diferencia que tenemos que llamar, este interceptor en el nivel de re-plantilla es un nivel demasiado alto, ¿verdad? necesita esto a nivel de solicitud: generalmente RestTemplate es un @Bean en la configuración de arranque de primavera
Kalpesh Soni el
21

Si, como yo, te costó encontrar un ejemplo que use encabezados con autenticación básica y la API de intercambio de plantillas de descanso, esto es lo que finalmente resolví ...

private HttpHeaders createHttpHeaders(String user, String password)
{
    String notEncoded = user + ":" + password;
    String encodedAuth = Base64.getEncoder().encodeToString(notEncoded.getBytes());
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    headers.add("Authorization", "Basic " + encodedAuth);
    return headers;
}

private void doYourThing() 
{
    String theUrl = "http://blah.blah.com:8080/rest/api/blah";
    RestTemplate restTemplate = new RestTemplate();
    try {
        HttpHeaders headers = createHttpHeaders("fred","1234");
        HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
        ResponseEntity<String> response = restTemplate.exchange(theUrl, HttpMethod.GET, entity, String.class);
        System.out.println("Result - status ("+ response.getStatusCode() + ") has body: " + response.hasBody());
    }
    catch (Exception eek) {
        System.out.println("** Exception: "+ eek.getMessage());
    }
}
Dave
fuente
11

Llamar a una API RESTful usando RestTemplate

Ejemplo 1:

RestTemplate restTemplate = new RestTemplate();
// Add the Jackson message converter
restTemplate.getMessageConverters()
                .add(new MappingJackson2HttpMessageConverter());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Basic XXXXXXXXXXXXXXXX=");
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
restTemplate.getInterceptors()
                .add(new BasicAuthorizationInterceptor(USERID, PWORD));
String requestJson = getRequetJson(Code, emailAddr, firstName, lastName);
response = restTemplate.postForObject(URL, requestJson, MYObject.class);
        

Ejemplo 2

RestTemplate restTemplate = new RestTemplate();
String requestJson = getRequetJson(code, emil, name, lastName);
HttpHeaders headers = new HttpHeaders();
String userPass = USERID + ":" + PWORD;
String authHeader =
    "Basic " + Base64.getEncoder().encodeToString(userPass.getBytes());
headers.set(HttpHeaders.AUTHORIZATION, authHeader);
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
HttpEntity<String> request = new HttpEntity<String>(requestJson, headers);
ResponseEntity<MyObject> responseEntity;
responseEntity =
    this.restTemplate.exchange(URI, HttpMethod.POST, request, Object.class);
responseEntity.getBody()

El getRequestJsonmétodo crea un objeto JSON:

private String getRequetJson(String Code, String emailAddr, String name) {
    ObjectMapper mapper = new ObjectMapper();
    JsonNode rootNode = mapper.createObjectNode();
    ((ObjectNode) rootNode).put("code", Code);
    ((ObjectNode) rootNode).put("email", emailAdd);
    ((ObjectNode) rootNode).put("firstName", name);
    String jsonString = null;
    try {
        jsonString = mapper.writerWithDefaultPrettyPrinter()
                               .writeValueAsString(rootNode);
    }
    catch (JsonProcessingException e) {
        e.printStackTrace();
    }
    return jsonString;
}
Vaquar Khan
fuente
4

Aquí hay una respuesta simple. Espero que ayude a alguien.

import org.springframework.boot.devtools.remote.client.HttpHeaderInterceptor;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate;


public String post(SomeRequest someRequest) {
    // create a list the headers 
    List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
    interceptors.add(new HttpHeaderInterceptor("Accept", MediaType.APPLICATION_JSON_VALUE));
    interceptors.add(new HttpHeaderInterceptor("ContentType", MediaType.APPLICATION_JSON_VALUE));
    interceptors.add(new HttpHeaderInterceptor("username", "user123"));
    interceptors.add(new HttpHeaderInterceptor("customHeader1", "c1"));
    interceptors.add(new HttpHeaderInterceptor("customHeader2", "c2"));
    // initialize RestTemplate
    RestTemplate restTemplate = new RestTemplate();
    // set header interceptors here
    restTemplate.setInterceptors(interceptors);
    // post the request. The response should be JSON string
    String response = restTemplate.postForObject(Url, someRequest, String.class);
    return response;
}
Tunde Michael
fuente
10
Su código utilizará Spring Devtools como una dependencia de producción (al importar org.springframework.boot.devtools.remote.client.HttpHeaderInterceptor) ...
snorbi