java 春季启动:RestTemplate postForObject 400 错误请求

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26690778/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 10:24:17  来源:igfitidea点击:

SPRING BOOT: RestTemplate postForObject 400 bad request

javarestspring-mvcspring-boot

提问by Orvyl

I keep receiving a 400 BAD request when sending a POST request using RestTemplate. Here's my code:

使用 RestTemplate 发送 POST 请求时,我不断收到 400 BAD 请求。这是我的代码:

    MultiValueMap<String, Object> requestBody = new LinkedMultiValueMap<String, Object>();
    requestBody.add("message_id", "msgid");
    requestBody.add("message", "qwerty");
    requestBody.add("client_id", "111");
    requestBody.add("secret_key", "222");

    MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
    headers.add("Accept", "application/json");
    headers.add("Content-Type", "application/json");

    HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<MultiValueMap<String, String>>(requestBody, headers);

    RestTemplate restTemplate = new RestTemplate();
    String response = restTemplate.postForObject("https://abc.com/api/request", httpEntity, String.class);
    JSONParser parser = new JSONParser();
    try {
        JSONObject jsonObject = (JSONObject) parser.parse(response);
        System.out.println(jsonObject.get("status"));
    } catch (ParseException e) {
        e.printStackTrace();
    }

What I am trying to achive is to convert the ff. php code to spring:

我想要实现的是转换ff。php 代码到 spring:

<?php
$arr_post_body = array(
  "message_id" => "qwerty",
  "message" => "Welcome to My life!",
  "client_id" => "111",
  "secret_key" => "222"
);

$query_string = "";
foreach($arr_post_body as $key => $frow)
{
    $query_string .= '&'.$key.'='.$frow;
}

$URL = "https://abc.com/api/request";
$curl_handler = curl_init();
curl_setopt($curl_handler, CURLOPT_URL, $URL);
curl_setopt($curl_handler, CURLOPT_POST, count($arr_post_body));
curl_setopt($curl_handler, CURLOPT_POSTFIELDS, $query_string);
curl_setopt($curl_handler, CURLOPT_RETURNTRANSFER, TRUE);
$response = curl_exec($curl_handler);
curl_close($curl_handler);
exit(0);

?>

Is there something wrong? Please take note that I am POSTing to an external link(API) and it is HTTPS.

有什么不对?请注意,我正在发布到外部链接(API),它是 HTTPS。

回答by RE350

Did you test it after adding accept and content type in your HTTP headers like below?

在像下面这样的 HTTP 标头中添加接受和内容类型后,您是否对其进行了测试?

MultiValueMap<String, Object> headers = new LinkedMultiValueMap<String, Object>();
headers.add("Accept", "application/json");
headers.add("Content-Type", "application/json");

Then add your request body and make postForObjectcall using RestTemplate.

然后添加您的请求正文并使用RestTemplate进行postForObject调用。

回答by The Saint

Any time you are a expecting/getting data back after a POST request using Spring's REST Template, the best method to use is restTemplate.exchange(), not restTemplate.postForObject().

任何时候当您使用 Spring 的 REST 模板在 POST 请求之后期望/获取数据时,最好的使用方法是restTemplate.exchange(),而不是restTemplate.postForObject()

So your code should look something like this:

所以你的代码应该是这样的:

HttpHeader headers = new HttpHeaders();
headers.add("Content-Type", MediaType.APPLICATION_JSON.toString());
headers.add("Accept", MediaType.APPLICATION_JSON.toString());

MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<String, String>();
requestBody.add("message_id", "msgid");
requestBody.add("message", "qwerty");
requestBody.add("client_id", "111");
requestBody.add("secret_key", "222");

HttpEntity formEntity = new HttpEntity<MultiValueMap<String, String>>(requestBody, headers);

ResponseEntity<AccessToken> response = 
                restTemplate.exchange("https://abc.com/api/request", HttpMethod.POST, 
                                      formEntity, YourPojoThatMapsToJsonResponse.class);

Do make a note here of the YourPojoThatMapsToJsonResponse.class at the very end. The exchange() method will automatically look at your JSON response and attempt to convert it to a POJO you have already defined that maps to that JSON structure. In other words, you should have already created that class. If you haven't, JSONParser.class might work in your case but there are no guarantees.

请在此处记下最后的 YourPojoThatMapsToJsonResponse.class。exchange() 方法将自动查看您的 JSON 响应并尝试将其转换为您已定义的映射到该 JSON 结构的 POJO。换句话说,您应该已经创建了该类。如果没有, JSONParser.class 可能适用于您的情况,但不能保证。

Try this out and let me know how it goes.

试试这个,让我知道它是怎么回事。

回答by Leopold Gault

As explained by The Saint and RE350, this is most likely an HTTP header issue. Here is how I solved it.

正如 The Saint 和 RE350 所解释的,这很可能是 HTTP 标头问题。这是我解决它的方法。

1- Identify which HTTP header you need to use

1- 确定您需要使用哪个 HTTP 标头

Use Postman (chrome) to make the HTTP call (the same one that you want to perform with RestTemplate). It should be successful. Open the Network tab of the Inspect Elementtoolto inspect the headers of your HTTP request.

使用 Postman (chrome) 进行 HTTP 调用(与您要使用 RestTemplate 执行的调用相同)。它应该是成功的。打开Inspect Element工具Network 选项卡以检查 HTTP 请求的标头。

2- Compare those headers with the ones used by RestTemplate

2- 将这些标头与 RestTemplate 使用的标头进行比较

Configure the TCP/IP Monitor of your Eclipseto monitor localhost:8081, and in your code, replace the target url of your restTemplate by localhost:8081. restTemplate.exchange("http://localhost:8081", HttpMethod.POST, httpEntity, String.class);Run your app; you'll be able to see which HTTP headers are used in the TCP/IP Monitor.

配置EclipseTCP/IP 监视器以监视 localhost:8081,并在您的代码中将您的 restTemplate 的目标 url 替换为 localhost:8081。 restTemplate.exchange("http://localhost:8081", HttpMethod.POST, httpEntity, String.class);运行你的应用程序;您将能够看到 TCP/IP 监视器中使用了哪些 HTTP 标头。

3- Configure the headers used by RestTemplate to match Postman's ones

3- 配置 RestTemplate 使用的标头以匹配 Postman 的标头

Get inspiration from Zacran's post to configure the headers.

Zacran 的帖子中获得灵感来配置 headers