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

Posted

技术标签:

【中文标题】春季启动:RestTemplate postForObject 400 错误请求【英文标题】:SPRING BOOT: RestTemplate postForObject 400 bad request 【发布时间】:2014-12-28 17:22:56 【问题描述】:

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

我想要实现的是转换 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);

?>

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

【问题讨论】:

【参考方案1】:

您是否在如下所示的 HTTP 标头中添加了接受和内容类型后对其进行了测试?

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

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

【讨论】:

【参考方案2】:

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

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

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

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

试试这个,让我知道结果如何。

【讨论】:

【参考方案3】:

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

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

使用 Postman (chrome) 进行 HTTP 调用(与您希望使用 RestTemplate 执行的调用相同)。它应该是成功的。打开 Network tab of the Inspect Element tool 以检查 HTTP 请求的标头。

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

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

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

从Zacran's post to configure the headers获得灵感。

【讨论】:

以上是关于春季启动:RestTemplate postForObject 400 错误请求的主要内容,如果未能解决你的问题,请参考以下文章

如何使用@WebMvcTest 春季测试在模拟服务中注入模拟的restTemplate

WebClient 与 RestTemplate

传递 POST 请求。春季安全。休息模板。杰克逊转换器

IndexOutOfBoundsException 春季批处理和春季启动

RestTemplate、Spring 启动、POST

春季启动批处理到具有多个作业的春季云任务