Richiesta POST tramite RestTemplate in JSON


126

Non ho trovato alcun esempio su come risolvere il mio problema, quindi voglio chiederti aiuto. Non posso semplicemente inviare una richiesta POST utilizzando l'oggetto RestTemplate in JSON

Ogni volta che ricevo:

org.springframework.web.client.HttpClientErrorException: 415 Tipo di supporto non supportato

Uso RestTemplate in questo modo:

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

Qual è la mia colpa?


1
@troyfolger l'url non è più valido
Noremac

Grazie - questo collegamento funziona al momento della stesura di questo articolo: spring.io/guides/gs/consuming-rest
troyfolger

Per risolvere il problema specifico dell'OP, sopra, probabilmente ti manca un'intestazione HTTP con il tipo di contenuto appropriato, vedi la risposta di morganw09dev di seguito.
troyfolger

Questi problemi sono principalmente legati alla configurazione dell'API del server. Puoi testare l'API del server utilizzando un client autonomo (come Postman) e replicare le stesse intestazioni nella richiesta. Almeno nel mio caso che ha fatto il trucco.
Linus

1
@ Johnny B, se è stata data una risposta, si prega di contrassegnare la risposta
Vishal

Risposte:


162

Questa tecnica ha funzionato per me:

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

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

Spero che aiuti


3
si prega di spiegare quale riga deve restituire il risultato della richiesta http
gstackoverflow

Per me non è stato necessario specificare alcuna intestazione. Ho usato HttpEntity che accetta un singolo parametro.
Constantino Cronemberger

24
metodo .put()è void!
membri suonano il

4
Utilizzando postForEntity(url, entity, String.class)opere al posto diput(url, entity)
Janac Meena

1
@Kanu, requestJson è una stringa JSON valida o qualcos'altro?
Deva

95

Ho riscontrato questo problema durante il tentativo di eseguire il debug di un endpoint REST. Ecco un esempio di base che utilizza la classe RestTemplate di Spring per effettuare una richiesta POST che ho usato. Mi ci è voluto un bel po 'di tempo per mettere insieme il codice da luoghi diversi per ottenere una versione funzionante.

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

Il particolare parser JSON del mio endpoint rest utilizzava le virgolette doppie necessarie intorno ai nomi dei campi, ecco perché ho evitato le virgolette doppie nella mia stringa requestJson.


u può Please help me su questo stackoverflow.com/questions/42240927/...
FaisalAhmed

Spring può utilizzare i convertitori di messaggi per convertire automaticamente l'oggetto Java in json come ha fatto nell'API Restful con RestTemplate?
autunno

1
L'impostazione del tipo di supporto su APPLICATION_JSON è la chiave per risolvere il problema.
Pete T

Ho risolto il mio problema utilizzando HttpEntity <String> entity = new HttpEntity <String> (requestJson, headers); questa linea
Ved Prakash

76

Ho utilizzato il modello di riposo con JSONObjects come segue:

// 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
}

Grazie - il metodo JSONObject toString è stato utile per me, mi ha aiutato a ottenere il mio JSONString accurato.
Simon

1
Come sviluppare il codice sopra per questo: curl -vvv -X POST " localhost: 8080 / SillyService_SRC / oauth /… "?
Pra_A

@Mikael Lepistö Come posso recuperare questi parametri da json all'estremità del server ??
KJEjava48

@ KJEjava48 Non capisco cosa intendi ... questo è il codice lato server nella risposta. Se stai pensando a come analizzare la risposta json, dipende dal framework che stai utilizzando.
Mikael Lepistö

@ MikaelLepistö Intendo come analizzare la risposta json dall'altra parte, incluso come ricevere la risposta in java? Hai pubblicato solo il codice per un'estremità (cioè, lato server).
KJEjava48

13

Come specificato qui, immagino che sia necessario aggiungere un messageConverterper MappingJacksonHttpMessageConverter


10

Se stai usando Spring 3.0, un modo semplice per evitare org.springframework.web.client.HttpClientErrorException: 415 eccezione del tipo di supporto non supportato , è includere i file jar jackson nel tuo classpath e utilizzare l' mvc:annotation-drivenelemento config. Come specificato qui .

Mi stavo strappando i capelli cercando di capire perché l' app mvc-ajax funzionava senza alcuna configurazione speciale per il file MappingJacksonHttpMessageConverter. Se leggi attentamente l'articolo che ho linkato sopra:

Sotto le copertine, Spring MVC delega a un HttpMessageConverter per eseguire la serializzazione. In questo caso, Spring MVC richiama un MappingJacksonHttpMessageConverter basato sul processore Jackson JSON. Questa implementazione viene abilitata automaticamente quando si utilizza l'elemento di configurazione mvc: annotation-driven con Jackson presente nel proprio classpath .


7

L'errore "415 Unsupported Media Type" indica che il server non accetterà la tua richiesta POST. La tua richiesta va assolutamente bene, è il server che è configurato male.

MappingJacksonHttpMessageConverterimposterà automaticamente l'intestazione del tipo di contenuto della richiesta su application/json, e la mia ipotesi è che il tuo server lo stia rifiutando. Non ci hai detto nulla sulla configurazione del tuo server, quindi non posso davvero consigliarti su questo.


7

Lo sto facendo in questo modo e funziona.

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

// Passa qui le intestazioni

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

Spero che questo ti aiuti


4

Stavo riscontrando questo problema e sto usando RestTemplate di Spring sul client e Spring Web sul server. Entrambe le API hanno una segnalazione degli errori molto scarsa, il che le rende estremamente difficili da sviluppare.

Dopo molte ore di tentativi di tutti i tipi di esperimenti, ho capito che il problema era causato dal passaggio di un riferimento nullo per il corpo del POST invece dell'elenco previsto. Presumo che RestTemplate non possa determinare il tipo di contenuto da un oggetto nullo, ma non se ne lamenta. Dopo aver aggiunto le intestazioni corrette, ho iniziato a ricevere un'eccezione lato server diversa in primavera prima di inserire il mio metodo di servizio.

La correzione consisteva nel passare un elenco vuoto dal client invece di null. Non sono richieste intestazioni poiché il tipo di contenuto predefinito viene utilizzato per gli oggetti non nulli.


3

Questo codice funziona per me;

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

sto usando un approccio molto simile e NON ha funzionato per me. per qualche motivo il mio equivalente della tua "mappa" non viene convertito in json o incluso come corpo in uscita, ovvero il servizio di destinazione NON vede alcun carico utile.
abdel

2

Se non desideri elaborare la risposta

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

Se hai bisogno di una risposta per elaborare

String result = restTemplate.postForObject(url, entity, String.class);

0

Per me si è verificato un errore con questa configurazione:

AndroidAnnotations Spring Android RestTemplate Module e ...

GsonHttpMessageConverter

Le annotazioni Android hanno alcuni problemi con questo convertito per generare POSTrichiesta senza parametro. Semplicemente il parametro lo ha new Object()risolto per me.


0

Perché lavorare più duramente di quanto devi? postForEntityaccetta un semplice Mapoggetto come input. Quanto segue funziona bene per me durante la scrittura di test per un determinato endpoint REST in primavera. Credo che sia il modo più semplice possibile per effettuare una richiesta POST JSON in primavera:

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

0

Se non vuoi mappare il JSON da solo, puoi farlo come segue:

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

0

Ho provato come segue nell'avvio di primavera:

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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.