Demande POST via RestTemplate en JSON

126

Je n'ai trouvé aucun exemple pour résoudre mon problème, je veux donc vous demander de l'aide. Je ne peux pas simplement envoyer une requête POST à ​​l'aide de l'objet RestTemplate dans JSON

Chaque fois que je reçois:

org.springframework.web.client.HttpClientErrorException: 415 Type de support non pris en charge

J'utilise RestTemplate de cette manière:

...
restTemplate = new RestTemplate();
List<HttpMessageConverter<?>> list = new ArrayList<HttpMessageConverter<?>>();
list.add(new MappingJacksonHttpMessageConverter());
restTemplate.setMessageConverters(list);
...
Payment payment= new Payment("Aa4bhs");
Payment res = restTemplate.postForObject("http://localhost:8080/aurest/rest/payment", payment, Payment.class);

Quelle est ma faute?

Johnny B
la source
1
@troyfolger l'url n'est plus valide
Noremac
Merci - ce lien fonctionne au moment de la rédaction de cet article: spring.io/guides/gs/consuming-rest
troyfolger
Pour résoudre le problème spécifique de l'OP, ci-dessus, il vous manque probablement un en-tête HTTP avec un type de contenu approprié, voir la réponse de morganw09dev ci-dessous.
troyfolger
Ces problèmes sont principalement liés à la configuration de l'API du serveur. Vous testez l'API du serveur à l'aide d'un client autonome (comme Postman) et répliquez les mêmes en-têtes dans votre demande. Au moins dans mon cas, cela a fait le tour.
Linus
1
@Johnny B, si cela a été répondu, veuillez cocher la réponse
Vishal

Réponses:

162

Cette technique a fonctionné pour moi:

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<String> entity = new HttpEntity<String>(requestJson, headers);
ResponseEntity<String> response = restTemplate.put(url, entity);

J'espère que ça aide

kanu dialani
la source
3
Veuillez expliquer quelle ligne doit renvoyer le résultat de la requête http
gstackoverflow
Pour moi, il n'était pas nécessaire de spécifier des en-têtes. J'ai utilisé HttpEntity qui prend un seul paramètre.
Constantino Cronemberger
24
la méthode .put()est void!
publié
4
Utilisation d' postForEntity(url, entity, String.class)œuvres à la place deput(url, entity)
Janac Meena
1
@Kanu, requestJson est une chaîne JSON valide ou autre chose?
Deva
95

J'ai rencontré ce problème lors de la tentative de débogage d'un point de terminaison REST. Voici un exemple de base utilisant la classe RestTemplate de Spring pour faire une requête POST que j'ai utilisée. Il m'a fallu un peu de temps pour reconstituer le code de différents endroits pour obtenir une version fonctionnelle.

RestTemplate restTemplate = new RestTemplate();

String url = "endpoint url";
String requestJson = "{\"queriedQuestion\":\"Is there pain in your hand?\"}";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
String answer = restTemplate.postForObject(url, entity, String.class);
System.out.println(answer);

L'analyseur JSON particulier de mon point de terminaison de repos utilisait les guillemets doubles nécessaires autour des noms de champ, c'est pourquoi j'ai échappé les guillemets doubles dans ma chaîne requestJson.

Morgan Kenyon
la source
pouvez-vous s'il vous plaît m'aider sur ce stackoverflow.com/questions/42240927/…
FaisalAhmed
Spring peut-il utiliser les convertisseurs de messages pour convertir automatiquement l'objet Java en json comme il l'a fait dans l'API Restful avec RestTemplate?
automne
1
La définition du type de support sur APPLICATION_JSON est la clé pour résoudre le problème.
Pete T
J'ai résolu mon problème en utilisant HttpEntity <String> entity = new HttpEntity <String> (requestJson, headers); cette ligne
Ved Prakash
76

J'ai utilisé le modèle de repos avec JSONObjects comme suit:

// create request body
JSONObject request = new JSONObject();
request.put("username", name);
request.put("password", password);

// set headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(request.toString(), headers);

// send request and parse result
ResponseEntity<String> loginResponse = restTemplate
  .exchange(urlString, HttpMethod.POST, entity, String.class);
if (loginResponse.getStatusCode() == HttpStatus.OK) {
  JSONObject userJson = new JSONObject(loginResponse.getBody());
} else if (loginResponse.getStatusCode() == HttpStatus.UNAUTHORIZED) {
  // nono... bad credentials
}
Mikael Lepistö
la source
Merci - la méthode JSONObject toString m'a été utile, elle m'a aidé à obtenir ma JSONString précise.
Simon
1
Comment développer le code ci-dessus pour cela: curl -vvv -X POST " localhost: 8080 / SillyService_SRC / oauth /… "?
Pra_A
@Mikael Lepistö Comment puis-je récupérer ces paramètres de json à la fin du serveur ??
KJEjava48
@ KJEjava48 Je ne comprends pas ce que vous voulez dire ... c'est le code côté serveur dans la réponse. Si vous pensez comment analyser la réponse json, cela dépend du framework que vous utilisez.
Mikael Lepistö
@ MikaelLepistö Je veux dire comment analyser la réponse json à l'autre bout, y compris comment recevoir la réponse en java ?? Vous n'avez posté que le code pour une extrémité (c'est-à-dire côté serveur).
KJEjava48
13

Comme spécifié ici, je suppose que vous devez ajouter un messageConverterpour MappingJacksonHttpMessageConverter

Raghuram
la source
10

Si vous utilisez Spring 3.0, un moyen simple d'éviter l' exception org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type , consiste à inclure les fichiers jar jackson dans votre chemin de classe et à utiliser l' mvc:annotation-drivenélément config. Comme spécifié ici .

Je m'arrachais les cheveux en essayant de comprendre pourquoi l'application mvc-ajax fonctionnait sans aucune configuration spéciale pour le MappingJacksonHttpMessageConverter. Si vous lisez attentivement l'article que j'ai lié ci-dessus:

Sous les couvertures, Spring MVC délègue à un HttpMessageConverter pour effectuer la sérialisation. Dans ce cas, Spring MVC appelle un MappingJacksonHttpMessageConverter construit sur le processeur Jackson JSON. Cette implémentation est activée automatiquement lorsque vous utilisez l'élément de configuration mvc: annotation-driven avec Jackson présent dans votre classpath .

Mike G
la source
7

L'erreur «415 Unsupported Media Type» vous indique que le serveur n'acceptera pas votre demande POST. Votre demande est tout à fait correcte, c'est le serveur qui est mal configuré.

MappingJacksonHttpMessageConverterdéfinira automatiquement l'en-tête de type de contenu de la demande sur application/json, et je suppose que votre serveur le rejette. Cependant, vous ne nous avez rien dit sur la configuration de votre serveur, donc je ne peux pas vraiment vous conseiller à ce sujet.

skaffman
la source
7

Je fais de cette façon et ça marche.

HttpHeaders headers = createHttpHeaders(map);
public HttpHeaders createHttpHeaders(Map<String, String> map)
{   
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    for (Entry<String, String> entry : map.entrySet()) {
        headers.add(entry.getKey(),entry.getValue());
    }
    return headers;
}

// Passez les en-têtes ici

 String requestJson = "{ // Construct your JSON here }";
logger.info("Request JSON ="+requestJson);
HttpEntity<String> entity = new HttpEntity<String>(requestJson, headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
logger.info("Result - status ("+ response.getStatusCode() + ") has body: " + response.hasBody());
logger.info("Response ="+response.getBody());

J'espère que cela t'aides

Yakhoob
la source
4

J'avais ce problème et j'utilise RestTemplate de Spring sur le client et Spring Web sur le serveur. Les deux API ont des rapports d'erreurs très médiocres, ce qui les rend extrêmement difficiles à développer.

Après de nombreuses heures à essayer toutes sortes d'expériences, j'ai compris que le problème était causé par la transmission d'une référence nulle pour le corps POST au lieu de la liste attendue. Je présume que RestTemplate ne peut pas déterminer le type de contenu à partir d'un objet nul, mais ne s'en plaint pas. Après avoir ajouté les en-têtes corrects, j'ai commencé à obtenir une exception côté serveur différente dans Spring avant d'entrer ma méthode de service.

Le correctif consistait à transmettre une liste vide du client au lieu de null. Aucun en-tête n'est requis car le type de contenu par défaut est utilisé pour les objets non nuls.

Alex Worden
la source
3

Ce code fonctionne pour moi;

RestTemplate restTemplate = new RestTemplate();
Payment payment = new Payment("Aa4bhs");
MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
map.add("payment", payment);
HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<MultiValueMap<String, Object>>(map, headerObject);

Payment res = restTemplate.postForObject(url, httpEntity, Payment.class);
Ganesh
la source
J'utilise une approche très similaire et cela n'a PAS fonctionné pour moi. pour une raison quelconque, mon équivalent de votre «carte» n'est pas converti en json ou inclus en tant que corps sortant, c'est-à-dire que le service cible ne voit PAS de charge utile.
abdel
2

Si vous ne souhaitez pas traiter la réponse

private RestTemplate restTemplate = new RestTemplate();
restTemplate.postForObject(serviceURL, request, Void.class);

Si vous avez besoin d'une réponse pour traiter

String result = restTemplate.postForObject(url, entity, String.class);
Vipindas Gopalan
la source
0

Pour moi, une erreur s'est produite avec cette configuration:

AndroidAnnotations Spring Android RestTemplate Module et ...

GsonHttpMessageConverter

Les annotations Android ont quelques problèmes avec cette conversion pour générer POST requête sans paramètre. Simplement le paramètre l'a new Object()résolu pour moi.

Mateusz Jablonski
la source
0

Pourquoi travailler plus dur que nécessaire? postForEntityaccepte un Mapobjet simple comme entrée. Ce qui suit fonctionne très bien pour moi lors de l'écriture de tests pour un point de terminaison REST donné dans Spring. Je pense que c'est le moyen le plus simple de faire une requête JSON POST au printemps:

@Test
public void shouldLoginSuccessfully() {
  // 'restTemplate' below has been @Autowired prior to this
  Map map = new HashMap<String, String>();
  map.put("username", "bob123");
  map.put("password", "myP@ssw0rd");
  ResponseEntity<Void> resp = restTemplate.postForEntity(
      "http://localhost:8000/login",
      map,
      Void.class);
  assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
}
Érygz
la source
0

Si vous ne souhaitez pas mapper le JSON par vous-même, vous pouvez le faire comme suit:

RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter()));
ResponseEntity<String> result = restTemplate.postForEntity(uri, yourObject, String.class);
moritz.vieli
la source
0

J'ai essayé comme suit dans Spring Boot:

ParameterizedTypeReference<Map<String, Object>> typeRef = new ParameterizedTypeReference<Map<String, Object>>() {};
public Map<String, Object> processResponse(String urlendpoint)
{
    try{
    
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        //reqobj
        JSONObject request = new JSONObject();
        request.put("username", name);
        //Or Hashmap 
        Map<String, Object> reqbody =  new HashMap<>();
        reqbody.put("username",username);
        Gson gson = new Gson();//mvn plugin to convert map to String
        HttpEntity<String> entity = new HttpEntity<>( gson.toJson(reqbody), headers);
        ResponseEntity<Map<String, Object>> response = resttemplate.exchange(urlendpoint, HttpMethod.POST, entity, typeRef);//example of post req with json as request payload
        if(Integer.parseInt(response.getStatusCode().toString()) == HttpURLConnection.HTTP_OK)
        {
            Map<String, Object>  responsedetails = response.getBody();
            System.out.println(responsedetails);//whole json response as map object
            return responsedetails;
        }
    } catch (Exception e) {
        // TODO: handle exception
        System.err.println(e);
    }
    return null;
}
Parameshwar
la source