Solicitud POST a través de RestTemplate en JSON

126

No encontré ningún ejemplo de cómo resolver mi problema, por lo que quiero pedirle ayuda. No puedo simplemente enviar una solicitud POST usando el objeto RestTemplate en JSON

Cada vez que obtengo:

org.springframework.web.client.HttpClientErrorException: 415 Tipo de medio no admitido

Yo uso RestTemplate de esta manera:

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

¿Qué es mi culpa?

Johnny B
fuente
1
@troyfolger la url ya no es válida
Noremac
Gracias: este enlace funciona a partir de este escrito: spring.io/guides/gs/consuming-rest
troyfolger
Para abordar el problema específico de OP, arriba, probablemente le falte un encabezado HTTP con el tipo de contenido apropiado, consulte la respuesta de morganw09dev a continuación.
troyfolger
Estos problemas están relacionados principalmente con la configuración de la API del servidor. Usted prueba la API del servidor utilizando un cliente independiente (como Postman) y replica los mismos encabezados en su solicitud. Al menos en mi caso eso hizo el truco.
Linus
1
@Johnny B, si esto ha sido respondido, marque la respuesta
Vishal

Respuestas:

161

Esta técnica me funcionó:

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

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

espero que esto ayude

kanu dialani
fuente
3
explique qué fila debe devolver el resultado de la solicitud http
gstackoverflow
Para mí no fue necesario especificar ningún encabezado. He usado la HttpEntity que toma un solo parámetro.
Constantino Cronemberger
24
método .put()es void!
membersound
44
Uso de postForEntity(url, entity, String.class)obras en lugar deput(url, entity)
Janac Meena
1
@Kanu, requestJson es una cadena JSON válida o algo más?
Deva
95

Me encontré con este problema al intentar depurar un punto final REST. Aquí hay un ejemplo básico usando la clase RestTemplate de Spring para hacer una solicitud POST que usé. Me tomó bastante tiempo reunir el código de diferentes lugares para obtener una versión que funcione.

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

El analizador JSON particular de mi punto final de descanso estaba usando comillas dobles necesarias alrededor de los nombres de campo, por eso escapé de las comillas dobles en mi cadena de solicitud Json.

Morgan Kenyon
fuente
¿Puedes ayudarme en este stackoverflow.com/questions/42240927/…
FaisalAhmed
¿Puede Spring usar los convertidores de mensajes para convertir automáticamente el Objeto Java a json como lo hizo en Restful API con RestTemplate?
otoño
1
Establecer el tipo de medio en APPLICATION_JSON es la clave para resolver el problema.
Pete T
Resolví mi problema usando HttpEntity <String> entity = new HttpEntity <String> (requestJson, encabezados); esta línea
Ved Prakash
76

He estado usando la plantilla de descanso con JSONObjects de la siguiente manera:

// 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ö
fuente
Gracias: el método JSONObject toString fue útil para mí, me ayudó a obtener mi JSONString precisa.
Simon
1
¿Cómo se desarrolló el código anterior para esto: curl -vvv -X POST " localhost: 8080 / SillyService_SRC / oauth / ... "?
Pra_A
@Mikael Lepistö ¿Cómo puedo recuperar estos parámetros de json al final del servidor?
KJEjava48
@ KJEjava48 No entiendo qué quieres decir ... este es el código del lado del servidor en la respuesta. Si está pensando cómo analizar la respuesta json, depende del marco que esté utilizando.
Mikael Lepistö
@ MikaelLepistö Me refiero a cómo analizar la respuesta json en el otro extremo, incluida la forma de recibir la respuesta en Java. Ha publicado solo el código para un extremo (es decir, el lado del servidor).
KJEjava48
13

Como se especifica aquí , supongo que debe agregar un messageConverterpara MappingJacksonHttpMessageConverter

Raghuram
fuente
9

Si está utilizando Spring 3.0, una manera fácil de evitar la excepción org.springframework.web.client.HttpClientErrorException: 415 Tipo de medio no admitido es incluir los archivos jackson jar en su classpath y usar el mvc:annotation-drivenelemento config. Como se especifica aquí .

Me estaba arrancando el pelo tratando de entender por qué la aplicación mvc-ajax funcionaba sin ninguna configuración especial para el MappingJacksonHttpMessageConverter. Si lees el artículo que vinculé arriba de cerca:

Debajo de las cubiertas, Spring MVC delega en un HttpMessageConverter para realizar la serialización. En este caso, Spring MVC invoca un MappingJacksonHttpMessageConverter integrado en el procesador Jackson JSON. Esta implementación se habilita automáticamente cuando utiliza el elemento de configuración mvc: anotado con Jackson presente en su classpath .

Mike G
fuente
7

El error "415 Tipo de medio no admitido" le indica que el servidor no aceptará su solicitud POST. Su solicitud está absolutamente bien, es el servidor que está mal configurado.

MappingJacksonHttpMessageConverterconfigurará automáticamente el encabezado de tipo de contenido de solicitud en application/json, y supongo que su servidor lo está rechazando. Sin embargo, no nos ha dicho nada sobre la configuración de su servidor, por lo que realmente no puedo aconsejarle sobre eso.

skaffman
fuente
7

Lo estoy haciendo de esta manera y funciona.

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

// Pase los encabezados aquí

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

Espero que esto ayude

Yakhoob
fuente
4

Estaba teniendo este problema y estoy usando Spring's RestTemplate en el cliente y Spring Web en el servidor. Ambas API tienen informes de errores muy pobres, por lo que son extremadamente difíciles de desarrollar.

Después de muchas horas de probar todo tipo de experimentos, descubrí que el problema estaba siendo causado al pasar una referencia nula para el cuerpo POST en lugar de la Lista esperada. Supongo que RestTemplate no puede determinar el tipo de contenido de un objeto nulo, pero no se queja de ello. Después de agregar los encabezados correctos, comencé a obtener una excepción del lado del servidor diferente en Spring antes de ingresar a mi método de servicio.

La solución fue pasar una lista vacía del cliente en lugar de nula. No se requieren encabezados ya que el tipo de contenido predeterminado se usa para objetos no nulos.

Alex Worden
fuente
3

Este código me está funcionando;

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
fuente
Estoy usando un enfoque muy similar y NO me funcionó. por alguna razón, mi equivalente de su 'mapa' no se está convirtiendo a json o incluido como cuerpo saliente, es decir, el servicio de destino NO ve ninguna carga útil.
abdel
2

Si no quieres procesar la respuesta

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

Si necesita respuesta para procesar

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

Para mí, se produjo un error con esta configuración:

AndroidAnnotations Spring Android RestTemplate Module y ...

GsonHttpMessageConverter

Las anotaciones de Android tienen algunos problemas con esto convertido para generar POSTsolicitud sin parámetro. Simplemente el parámetro lo new Object()resolvió para mí.

Mateusz Jablonski
fuente
0

¿Por qué trabajar más duro de lo necesario? postForEntityacepta un Mapobjeto simple como entrada. Lo siguiente funciona bien para mí al escribir pruebas para un punto final REST dado en Spring. Creo que es la forma más simple posible de hacer una solicitud JSON POST en Spring:

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

Si no desea asignar el JSON usted mismo, puede hacerlo de la siguiente manera:

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

Intenté lo siguiente en el arranque de 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;
}
Parameshwar
fuente