Żądanie POST przez RestTemplate w formacie JSON

126

Nie znalazłem żadnego przykładu, jak rozwiązać mój problem, więc chcę prosić Cię o pomoc. Nie mogę po prostu wysłać żądania POST za pomocą obiektu RestTemplate w JSON

Za każdym razem, gdy dostaję:

org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type

Używam RestTemplate w ten sposób:

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

Co jest moją winą?

Johnny B.
źródło
1
@troyfolger adres URL nie jest już ważny
Noremac
Dzięki - ten link działa w chwili pisania tego tekstu
troyfolger
Aby rozwiązać konkretny problem z OP, powyżej, prawdopodobnie brakuje nagłówka HTTP z odpowiednim typem treści, zobacz odpowiedź z morganw09dev poniżej.
troyfolger
Te problemy są głównie związane z konfiguracją interfejsu API serwera. Testujesz interfejs API serwera przy użyciu klienta autonomicznego (takiego jak Postman) i replikujesz te same nagłówki w żądaniu. Przynajmniej w moim przypadku to zrobiło Sztukę.
Linus
1
@Johnny B, jeśli odpowiedź na to pytanie została udzielona, ​​zaznacz odpowiedź
Vishal

Odpowiedzi:

162

Ta technika zadziałała dla mnie:

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

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

mam nadzieję, że to pomoże

kanu dialani
źródło
3
proszę wyjaśnić, który wiersz powinien zwrócić wynik żądania http
gstackoverflow
U mnie nie było potrzeby określania żadnych nagłówków. Użyłem HttpEntity, który przyjmuje pojedynczy parametr.
Constantino Cronemberger
24
metoda .put()jest void!
członkowie wokół
4
Korzystanie z postForEntity(url, entity, String.class)utworów w miejsceput(url, entity)
Janac Meena Janac Meena
1
@Kanu, requestJson to prawidłowy ciąg JSON czy coś innego?
Deva
95

Napotkałem ten problem podczas próby debugowania punktu końcowego REST. Oto podstawowy przykład użycia klasy RestTemplate Springa do wykonania żądania POST, którego użyłem. Sporo czasu zajęło mi zebranie kodu z różnych miejsc w celu uzyskania działającej wersji.

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

Konkretny parser JSON, w którym mój punkt końcowy korzystał z potrzebnych podwójnych cudzysłowów wokół nazw pól, dlatego uniknąłem podwójnych cudzysłowów w moim ciągu requestJson.

Morgan Kenyon
źródło
czy możesz mi pomóc w tym stackoverflow.com/questions/42240927/…
FaisalAhmed
Czy Spring może używać konwerterów komunikatów do automatycznej konwersji obiektu Java do formatu json, tak jak w Restful API z RestTemplate?
jesień
1
Ustawienie typu nośnika na APPLICATION_JSON jest kluczem do rozwiązania problemu.
Pete T,
Rozwiązałem swój problem za pomocą HttpEntity <String> entity = new HttpEntity <String> (requestJson, headers); ta linia
Ved Prakash
76

Używałem szablonu REST z JSONObjects w następujący sposób:

// 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ö
źródło
Dzięki - metoda JSONObject toString była dla mnie przydatna, pomogła mi uzyskać dokładność JSONtring.
Simon
1
Jak opracować powyższy kod w tym celu: curl -vvv -X POST " localhost: 8080 / SillyService_SRC / oauth /… "?
Pra_A
@Mikael Lepistö Jak mogę pobrać te parametry z json na końcu serwera?
KJEjava48
@ KJEjava48 Nie rozumiem, co masz na myśli ... to jest kod po stronie serwera w odpowiedzi. Jeśli zastanawiasz się, jak przeanalizować odpowiedź JSON, zależy to od używanej struktury.
Mikael Lepistö
@ MikaelLepistö Mam na myśli, jak przeanalizować odpowiedź json na drugim końcu, w tym jak otrzymać odpowiedź w java? Wysłałeś tylko kod dla jednego końca (tj. Po stronie serwera).
KJEjava48
13

Jak określono tutaj , myślę, że musisz dodać messageConverterdla MappingJacksonHttpMessageConverter

Raghuram
źródło
10

Jeśli używasz Spring 3.0, prostym sposobem na uniknięcie org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type , jest dołączenie plików jar jackson do ścieżki klas i użycie mvc:annotation-drivenelementu config. Jak określono tutaj .

Wyciągałem włosy, próbując dowiedzieć się, dlaczego aplikacja mvc-ajax działała bez specjalnej konfiguracji dla MappingJacksonHttpMessageConverter. Jeśli dokładnie przeczytałeś artykuł, do którego dołączyłem powyżej:

Pod okładkami Spring MVC deleguje do HttpMessageConverter w celu wykonania serializacji. W tym przypadku Spring MVC wywołuje MappingJacksonHttpMessageConverter zbudowany na procesorze Jackson JSON. Ta implementacja jest włączana automatycznie, gdy używasz elementu konfiguracji mvc: annotation-based z Jacksonem obecnym w ścieżce klas .

Mike G.
źródło
7

Błąd „415 Nieobsługiwany typ nośnika” informuje, że serwer nie akceptuje żądania POST. Twoje żądanie jest absolutnie w porządku, to serwer, który jest źle skonfigurowany.

MappingJacksonHttpMessageConverterautomatycznie ustawi nagłówek typu content-type żądania na application/jsoni domyślam się, że twój serwer to odrzuca. Nie powiedziałeś nam jednak nic o konfiguracji serwera, więc nie mogę Ci w tym doradzić.

skaffman
źródło
7

Robię w ten sposób i to działa.

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

// Tutaj podaj nagłówki

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

Mam nadzieję że to pomoże

Yakhoob
źródło
4

Pojawił się ten problem i używam Springa RestTemplate na kliencie i Spring Web na serwerze. Oba interfejsy API mają bardzo słabe raportowanie błędów, co sprawia, że ​​ich programowanie jest niezwykle trudne.

Po wielu godzinach próbowania wszelkiego rodzaju eksperymentów doszedłem do wniosku, że problem jest spowodowany przekazaniem zerowej referencji dla treści POST zamiast oczekiwanej listy. Zakładam, że RestTemplate nie może określić typu zawartości z obiektu o wartości null, ale nie narzeka na to. Po dodaniu poprawnych nagłówków zacząłem otrzymywać inny wyjątek po stronie serwera w Spring przed wejściem do mojej metody usługi.

Poprawka polegała na przekazaniu pustej listy od klienta zamiast wartości null. Nie są wymagane żadne nagłówki, ponieważ domyślny typ zawartości jest używany dla obiektów niezerowych.

Alex Worden
źródło
3

Ten kod działa dla mnie;

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
źródło
używam bardzo podobnego podejścia i to NIE działa dla mnie. z jakiegoś powodu mój odpowiednik twojej „mapy” nie jest konwertowany do json ani włączany jako treść wychodząca, tj. usługa docelowa NIE widzi żadnego ładunku.
abdel
2

Jeśli nie chcesz przetwarzać odpowiedzi

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

Jeśli potrzebujesz odpowiedzi w procesie

String result = restTemplate.postForObject(url, entity, String.class);
Vipindas Gopalan
źródło
0

U mnie wystąpił błąd podczas tej konfiguracji:

AndroidAnnotations Spring Android RestTemplate Module i ...

GsonHttpMessageConverter

Adnotacje na Androida mają pewne problemy z tym przekonwertowanym na generowanie POSTżądania bez parametru. Po prostu parametr new Object()rozwiązał to za mnie.

Mateusz Jabłoński
źródło
0

Po co pracować ciężej niż musisz? postForEntityakceptuje prosty Mapobiekt jako dane wejściowe. Poniższe działa dobrze dla mnie podczas pisania testów dla danego punktu końcowego REST na wiosnę. Uważam, że jest to najprostszy możliwy sposób na wykonanie żądania JSON POST na wiosnę:

@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
źródło
0

Jeśli nie chcesz samodzielnie mapować JSON, możesz to zrobić w następujący sposób:

RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter()));
ResponseEntity<String> result = restTemplate.postForEntity(uri, yourObject, String.class);
moritz.vieli
źródło
0

Spróbowałem w następujący sposób w butach wiosennych:

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
źródło