POST-запрос через RestTemplate в JSON

126

Я не нашел примера, как решить свою проблему, поэтому хочу попросить вас о помощи. Я не могу просто отправить запрос POST с помощью объекта RestTemplate в JSON

Каждый раз получаю:

org.springframework.web.client.HttpClientErrorException: 415 Неподдерживаемый тип носителя

Я использую RestTemplate таким образом:

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

В чем я виновата?

Джонни Б.
источник
1
@troyfolger, URL больше недействителен
Noremac
Спасибо - эта ссылка работает на момент написания: spring.io/guides/gs/consuming-rest
troyfolger
Чтобы решить конкретную проблему OP, описанную выше, возможно, вам не хватает заголовка HTTP с соответствующим типом содержимого, см. Ответ от morganw09dev ниже.
тройфолгер
Эти проблемы в основном связаны с конфигурацией API сервера. Вы тестируете серверный API с помощью автономного клиента (например, Postman) и реплицируете те же заголовки в свой запрос. По крайней мере, в моем случае это помогло.
Linus
1
@Johnny B, если на это есть ответ, отметьте ответ
Vishal

Ответы:

162

Эта техника сработала для меня:

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

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

надеюсь, это поможет

Кану Диалани
источник
3
пожалуйста, объясните, какая строка должна возвращать результат http-запроса
gstackoverflow
Мне не нужно было указывать какие-либо заголовки. Я использовал HttpEntity, который принимает единственный параметр.
Константино Кронембергер
24
метод .put()есть void!
membersound
4
Использование postForEntity(url, entity, String.class)произведений вместоput(url, entity)
Янак Мина
1
@Kanu, requestJson - это действительная строка JSON или что-то еще?
Deva
95

Я столкнулся с этой проблемой при попытке отладки конечной точки REST. Вот базовый пример использования класса Spring RestTemplate для выполнения запроса POST, который я использовал. Мне потребовалось довольно много времени, чтобы собрать воедино код из разных мест, чтобы получить рабочую версию.

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

Конкретный парсер JSON, моя конечная точка отдыха, использовал необходимые двойные кавычки вокруг имен полей, поэтому я избежал двойных кавычек в моем requestJson String.

Морган Кеньон
источник
не могли бы вы помочь мне в этом stackoverflow.com/questions/42240927/…
FaisalAhmed
Может ли Spring использовать конвертеры сообщений для автоматического преобразования объекта Java в json, как это было в Restful API с RestTemplate?
осень
1
Установка типа носителя на APPLICATION_JSON - ключ к решению проблемы.
Pete T
Я решил свою проблему, используя HttpEntity <String> entity = new HttpEntity <String> (requestJson, headers); this line
Ved Prakash
76

Я использовал шаблон отдыха с JSONObjects следующим образом:

// 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
}
Микаэль Лепистё
источник
Спасибо - метод JSONObject toString был мне полезен, он помог мне получить точную JSONString.
Саймон
1
Как разработать приведенный выше код для этого: curl -vvv -X POST " localhost: 8080 / SillyService_SRC / oauth /… "?
Pra_A
@Mikael Lepistö Как я могу получить эти параметры из json на стороне сервера ??
KJEjava48
@ KJEjava48 Я не понимаю, что вы имеете в виду ... это код на стороне сервера в ответе. Если вы думаете, как анализировать ответ json, это зависит от используемой вами структуры.
Микаэль Леписто
@ MikaelLepistö Я имею в виду, как анализировать ответ json на другом конце, в том числе как получить ответ на java? Вы разместили только код для одного конца (то есть на стороне сервера).
KJEjava48
13

Как указано здесь, я думаю, вам нужно добавить messageConverterдля MappingJacksonHttpMessageConverter

Raghuram
источник
10

Если вы используете Spring 3.0, простой способ избежать исключения org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type - включить файлы jar jackson в путь к классам и использовать mvc:annotation-drivenэлемент config. Как указано здесь .

Я вытаскивал волосы, пытаясь понять, почему приложение mvc-ajax работает без какой-либо специальной конфигурации для MappingJacksonHttpMessageConverter. Если вы внимательно прочитали статью, на которую я ссылался выше:

Под обложками Spring MVC делегирует HttpMessageConverter для выполнения сериализации. В этом случае Spring MVC вызывает MappingJacksonHttpMessageConverter, построенный на процессоре Jackson JSON. Эта реализация включается автоматически, когда вы используете элемент конфигурации, управляемый аннотациями mvc: с присутствием Джексона в вашем пути к классам .

Майк Джи
источник
7

Ошибка «415 Unsupported Media Type» сообщает вам, что сервер не примет ваш POST-запрос. С вашим запросом все в порядке, неправильно настроен сервер.

MappingJacksonHttpMessageConverterавтоматически установит заголовок типа содержимого запроса application/json, и я предполагаю, что ваш сервер отклоняет это. Однако вы ничего не сказали нам о настройке вашего сервера, поэтому я не могу вам посоветовать.

skaffman
источник
7

Я так делаю, и это работает.

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

// Передаем сюда заголовки

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

Надеюсь это поможет

Yakhoob
источник
4

У меня возникла эта проблема, и я использую Spring RestTemplate на клиенте и Spring Web на сервере. Оба API имеют очень плохую систему отчетов об ошибках, что чрезвычайно затрудняет их разработку.

После многих часов попыток всевозможных экспериментов я понял, что проблема была вызвана передачей нулевой ссылки для тела POST вместо ожидаемого списка. Я предполагаю, что RestTemplate не может определить тип содержимого по нулевому объекту, но не жалуется на это. После добавления правильных заголовков я начал получать в Spring другое исключение на стороне сервера перед тем, как ввести свой метод обслуживания.

Исправление заключалось в передаче от клиента пустого списка вместо нуля. Заголовки не требуются, поскольку тип содержимого по умолчанию используется для ненулевых объектов.

Алекс Уорден
источник
3

Этот код работает у меня;

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
источник
Я использую очень похожий подход, и он НЕ сработал для меня. по какой-то причине мой эквивалент вашей «карты» не конвертируется в json или не включается в качестве исходящего тела, т.е. целевая служба НЕ видит никакой полезной нагрузки.
abdel
2

Если вы не хотите обрабатывать ответ

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

Если вам нужен ответ на процесс

String result = restTemplate.postForObject(url, entity, String.class);
Випиндас Гопалан
источник
0

Для меня произошла ошибка с этой настройкой:

AndroidAnnotations Spring Android RestTemplate Module и ...

GsonHttpMessageConverter

Аннотации Android имеют некоторые проблемы с преобразованием для создания POSTзапроса без параметров. Просто параметр new Object()решил это за меня.

Матеуш Яблонски
источник
0

Зачем работать больше, чем нужно? postForEntityпринимает в Mapкачестве входных данных простой объект. Следующее отлично работает для меня при написании тестов для данной конечной точки REST в Spring. Я считаю, что это самый простой из возможных способов сделать запрос JSON POST в 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
источник
0

Если вы не хотите самостоятельно отображать JSON, вы можете сделать это следующим образом:

RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter()));
ResponseEntity<String> result = restTemplate.postForEntity(uri, yourObject, String.class);
moritz.vieli
источник
0

Я пробовал следующее при весенней загрузке:

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
источник