Comment définir un en-tête «Accept:» sur la demande Spring RestTemplate?

194

Je souhaite définir la valeur de Accept:dans une demande que je fais à l'aide de SpringRestTemplate .

Voici mon code de gestion des demandes 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;
}

et voici mon client 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);
}

Cela fonctionne pour moi; J'obtiens une chaîne JSON du côté serveur.

Ma question est: comment puis - je spécifier l' en- Accept:tête (par exemple application/json, application/xml...) et la méthode de demande (par exemple GET, POST...) lors de l' utilisation RestTemplate?

edaklij
la source

Réponses:

355

Je suggère d'utiliser l'une des exchangeméthodes qui accepte un HttpEntitypour lequel vous pouvez également définir le HttpHeaders. (Vous pouvez également spécifier la méthode HTTP que vous souhaitez utiliser.)

Par exemple,

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);

Je préfère cette solution car elle est fortement typée, c'est à dire. exchangeattend unHttpEntity .

Cependant, vous pouvez également le transmettre HttpEntitycomme requestargument à postForObject.

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

Ceci est mentionné dans le RestTemplate#postForObjectJavadoc .

Le requestparamètre peut être a HttpEntityafin d' ajouter des en-têtes HTTP supplémentaires à la requête .

Sotirios Delimanolis
la source
132

Vous pouvez définir un intercepteur "ClientHttpRequestInterceptor" dans votre RestTemplate pour éviter de définir l'en-tête à chaque fois que vous envoyez une requête.

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);
        }
    }

ensuite

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

RestTemplate restTemplate = new RestTemplate();
restTemplate.setInterceptors(interceptors);
Ammar
la source
Spring Boot 1.3 a un HttpHeaderInterceptor, nous n'avons donc pas besoin de créer notre propre implémentation de ClientHttpRequestInterceptor.
whistling_marmot
2
Pour une raison quelconque, HttpHeaderInterceptor n'est que dans spring-boot-devtools. Nous devons donc encore implémenter ClientHttpRequestInterceptor nous-mêmes. Je pense qu'il devrait être déplacé vers spring-web.
whistling_marmot
2
Est-il préférable d'ajouter des en-têtes par défaut à ClientHttpRequestFactory définis sur le modèle de repos au lieu d'ajouter des intercepteurs? PS, vous devez ajouter votre réponse dans une question distincte car cela concerne les en-têtes par défaut. J'ai dû chercher un moment pour arriver ici!
sbsatter
s'il y a deux services qui utilisent deux diff id / pass que nous devons appeler, cet intercepteur au niveau resttemplate est de niveau trop élevé, non? vous en avez besoin au niveau de la demande - généralement RestTemplate est un @Bean dans la configuration de démarrage de printemps
Kalpesh Soni
21

Si, comme moi, vous avez eu du mal à trouver un exemple qui utilise des en-têtes avec l'authentification de base et l'API d'échange de modèles restants, c'est ce que j'ai finalement élaboré ...

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
la source
11

Appel d'une API RESTful à l'aide de RestTemplate

Exemple 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);
        

Exemple 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()

La getRequestJsonméthode crée un objet 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
la source
4

Voici une réponse simple. J'espère que ça aide quelqu'un.

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
la source
10
Votre code utilisera Spring Devtools comme dépendance de production (en important org.springframework.boot.devtools.remote.client.HttpHeaderInterceptor) ...
snorbi