【问题标题】:GET request in RestTemplate in JSON在 JSON 中的 RestTemplate 中获取请求
【发布时间】:2017-06-27 19:44:53
【问题描述】:

一个看似超级简单的问题已经困扰了几天:

我正在使用application/json 中的 RestTemplate 发出一个简单的 GET 请求,但我不断收到

org.springframework.web.client.HttpClientErrorException: 400 Bad Request
    at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91)
    at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:636)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:592)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:552)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:470)

我做了研究并关注了这个tutorial,我还查看了这个POST request via RestTemplate in JSON 的解决方案。但他们都没有帮助,这是我的代码:

RestTemplate restTemplate = new RestTemplate();    
HttpHeaders requestHeaders = new HttpHeaders();    
requestHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
restTemplate.exchange(endpoint, HttpMethod.GET, requestEntity, String.class);

endpointhttp://localhost:8080/api/v1/items?itemIds=" + URLEncoder.encode(itemIds, "UTF-8") 在 Postman 中可以正常工作。 itemIds 是一个逗号分隔的列表,如下所示:

5400028914,5400029138,5400029138,5400029138,5400029138,5400028401,5400028918,5400028076,5400028726

我也尝试使用getForObject,如下所示:

String result = restTemplate.getForObject(endpoint, String.class);

这给了我这个错误:

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

我不确定我错过了什么或做错了什么,但相同的端点在 Postman 上完美运行,但唯一的区别是我在 Postman 应用程序中添加了 Content-Type 标头。

这是邮递员的请求:

GET /api/v1/items?itemIds=abc%2cdef%2cghi HTTP/1.1 Host: localhost:8080 Connection: keep-alive Postman-Token: 84790e06-86aa-fa8a-1047-238d6c931a68 Cache-Control: no-cache User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 Content-Type: application/json Accept: */* Accept-Encoding: gzip, deflate, sdch Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4

如果上面的代码有误,我该如何使用 RestTemplate 正确设置内容类型?

又一次深入研究,我已经启动 Wireshark 来捕获两个 HTTP 请求,以下是屏幕截图:

邮递员的请求:

来自我的 Java 代码的请求:

我仍然不明白为什么我的 Java 程序中的那个会抛出 400 而 Postman 中的那个却可以正常工作。

非常感谢。

【问题讨论】:

  • 你试过 getForObject() 和 getForEntity() 了吗?在您的情况下,它们可能比 exchange() 更好。
  • 转储您通过邮递员发送的请求并在此处发布。
  • 但是你为什么要使用内容类型的 GET 请求呢?内容类型是“请求正文的 MIME 类型(用于 POST 和 PUT 请求)。” en.wikipedia.org/wiki/List_of_HTTP_header_fields
  • 当然,我尝试了 getForObject(),请参阅我对原始帖子的编辑。我也会尝试 getForEntity 。 @zakariaamine
  • 感谢您指出。 @VladBochenin,但在这种情况下,我如何指定它的内容类型?谢谢。

标签: java spring http get resttemplate


【解决方案1】:

您不需要为 GET 方法设置“requestEntity”,试试这样的代码:

public ItemInfo getItemInfo() throws Exception {
    String url =
            "http://localhost:8080/api/v1/items?itemIds=abc";
    ObjectMapper objectMapper = new ObjectMapper();     
    ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
    String responseBody = response.getBody();
    handlerError(response, url);
    try {
        return objectMapper.readValue(responseBody, ItemInfo.class);
    } catch (IOException exception) {
        LOGGER.error("failed to send REST request", exception);
        throw new Exception(ErrorCode.NOT_AVAILABLE, url);
    }
}

private void handlerError(final ResponseEntity<String> response, final String url) throws Exception {
    String responseBody = response.getBody();
    try {
        if (RestUtil.isError(response.getStatusCode())) {
            ObjectMapper objectMapper = new ObjectMapper(); 
            MyInfoError myInfoError = objectMapper.readValue(responseBody, MyInfoError.class);
            throw new Exception(infoErreur, ErrorCode.UNKNOWN_CODE_ERROR);
        } else if (RestUtil.isNotFound(response.getStatusCode())) {
            throw new Exception(ErrorCode.NOT_AVAILABLE, "MyService");
        }
    } catch (IOException exception) {
        LOGGER.error("failed to send REST request", exception);
        throw new Exception(ErrorCode.NOT_AVAILABLE, url);
    }
}

我将其设为 NULL,因为 GET 方法不发送任何 JSON 请求正文/标头:

restTemplate.exchange(url, HttpMethod.GET, null, String.class);

或者:将您的标头放在 GET 方法中,如下所示:

RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<?> requestEntity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);

以 POST 为例,您需要如下设置 requestEntity:

ItemFormRequest request =
            new ItemFormRequest(1,"item no", "item name");
HttpEntity<ItemFormRequest> requestEntity = new HttpEntity<>(request);
        ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
        String responseBody = response.getBody();

希望有帮助:)

【讨论】:

  • 他们的HttpEntity 没有正文。在这种情况下,它只是作为标题的容器。
  • 是的,你是对的。我更改了答案,因为这里已经很晚了,而且我缺少一些问题信息:) 谢谢@SotiriosDelimanolis
  • 您的代码现在等同于他们的代码,所以我不明白您回答的目的。
  • 感谢您的帮助。
【解决方案2】:

好吧,最终,我的一位同事帮助我弄清楚了原因,信不信由你,就这么简单:

endpoint 是这样的: "http:localhost:8080/api/v1/items?itemIds=" + URLEncoder.encode(itemIds, "UTF-8");

不过应该​​是"http:localhost:8080/api/v1/items?itemIds=" + itemIds;

itemIds 只是一个逗号分隔的列表。

通过“UTF-8”架构进行 URLEncoder 编码后,这个逗号分隔的列表变为itemIds=5400028914%2C5400029138%2C5400029138%2C5400029138%2C5400029138%2C5400028401%2C5400028918%2C5400028076

来自

itemIds=5400028914,5400029138,5400029138,5400029138,5400029138,5400028401,5400028918,5400028076,5400028726

我们在使用RestTemplate时不需要URLEncoder对URL进行编码,有人可以在这里帮助我加深理解吗?

谢谢!

【讨论】:

    猜你喜欢
    • 2011-05-03
    • 1970-01-01
    • 1970-01-01
    • 2018-11-14
    • 2021-04-26
    • 1970-01-01
    • 2016-03-10
    相关资源
    最近更新 更多