Java 带有参数的Spring RestTemplate HTTP Post导致400错误请求错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22826887/
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-08-13 18:08:40  来源:igfitidea点击:

Spring RestTemplate HTTP Post with parameters cause 400 bad request error

javaandroidspringspring-android

提问by R4j

Possible duplicate Need help on RestTemplate Post Request with Body Parameters?and Spring RESTtemplate POSTbut these answers don't work for me
I tried to get access token from InstagramAPI by Spring Android. The request from Instagram 's documentlike this:

可能重复需要有关带有正文参数的 RestTemplate Post 请求的帮助吗?Spring RESTtemplate POST但这些答案对我不起作用
我试图Instagram通过 Spring Android从API获取访问令牌。来自Instagram 文档的请求是这样的:

curl \-F 'client_id=CLIENT-ID' \
-F 'client_secret=CLIENT-SECRET' \
-F 'grant_type=authorization_code' \
-F 'redirect_uri=YOUR-REDIRECT-URI' \
-F 'code=CODE' \https://api.instagram.com/oauth/access_token

Here is my request access token (After I get request token successful):

这是我的请求访问令牌(在我获得请求令牌成功后):

 MultiValueMap<String, String> mvm = new LinkedMultiValueMap<String, String>();
    mvm.add("client_id", INSTAGRAM_CILENT_ID);
    mvm.add("client_secret", INSTAGRAM_SECRET);
    mvm.add("grant_type", "authorization_code");
    mvm.add("redirect_uri", CALLBACKURL);
    mvm.add("code", requestToken);

    InstagramResult result = restTemplate .postForObject("https://api.instagram.com/oauth/access_token", mvm, InstagramResult .class);

The result mapping class:

结果映射类:

public class InstagramLogin {
   public String access_token;
   public InstagramUser user;
}

public class InstagramUser {
   public String id;
   public String username;
   public String full_name;
   public String profile_picture;
}

And the rest template:

其余模板:

   RestTemplate restTemplate = new RestTemplate();
    final List<HttpMessageConverter<?>> listHttpMessageConverters = new ArrayList< HttpMessageConverter<?> >(); 

    listHttpMessageConverters.add(new GsonHttpMessageConverter());
    listHttpMessageConverters.add(new FormHttpMessageConverter());
    listHttpMessageConverters.add(new StringHttpMessageConverter());
    restTemplate.setMessageConverters(listHttpMessageConverters);

But I always get 400 bad request error. Here is my stack trace:

但我总是收到 400 个错误的请求错误。这是我的堆栈跟踪:

04-03 09:32:45.366: W/RestTemplate(31709): POST request for "https://api.instagram.com/oauth/access_token" resulted in 400 (BAD REQUEST); invoking error handler
04-03 09:32:46.857: E//DefaultRequestRunner.java:138(31709): 09:32:46.862 Thread-32787 An exception occurred during request network execution :400 BAD REQUEST
04-03 09:32:46.857: E//DefaultRequestRunner.java:138(31709): org.springframework.web.client.HttpClientErrorException: 400 BAD REQUEST
04-03 09:32:46.857: E//DefaultRequestRunner.java:138(31709):    at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:76)
04-03 09:32:46.857: E//DefaultRequestRunner.java:138(31709):    at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:524)
04-03 09:32:46.857: E//DefaultRequestRunner.java:138(31709):    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:481)
04-03 09:32:46.857: E//DefaultRequestRunner.java:138(31709):    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:439)
04-03 09:32:46.857: E//DefaultRequestRunner.java:138(31709):    at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:317)

P/s: I am surely my parameter values are right, because I tested by curl and it worked fine.

P/s:我确定我的参数值是正确的,因为我通过 curl 测试过并且效果很好。

采纳答案by Roy Clarkson

A server will often return an HTTP 400 if the content type is not acceptable for a request. The curl example from instagram uses the -Fparameter which specifies multipart post data:

如果请求的内容类型不可接受,服务器通常会返回 HTTP 400。instagram 的 curl 示例使用-F指定多部分发布数据的参数:

-F, --form CONTENT  Specify HTTP multipart POST data (H)

Therefore, you may want to try explicitly setting the Content-type HTTP header in your RestTemplate request:

因此,您可能想尝试在 RestTemplate 请求中显式设置 Content-type HTTP 标头:

HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String, String>>(mvm, requestHeaders);
ResponseEntity<InstagramResult> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, InstagramResult.class);
InstagramResult result = response.getBody();

As mentioned earlier in the comments, a proxy tool like fiddler can be really useful for debugging. The challenge with this situation is that you are working with SSL, so these tools won't be able to "see" the encrypted communications without special configuration.

正如前面评论中提到的,像 fiddler 这样的代理工具对于调试非常有用。这种情况的挑战在于您正在使用 SSL,因此如果没有特殊配置,这些工具将无法“看到”加密的通信。

回答by Aarambh

HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(LINKEDIN_POST_URL);

List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("grant_type", grant_type));
nameValuePairs.add(new BasicNameValuePair("code", code));
nameValuePairs.add(new BasicNameValuePair("redirect_uri", redirect_uri);
nameValuePairs.add(new BasicNameValuePair("client_id", client_id));
nameValuePairs.add(new BasicNameValuePair("client_secret", client_secret));

httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);

And to convert your response to String. You can use:

并将您的响应转换为字符串。您可以使用:

EntityUtils.toString(response.getEntity());

I suppose you want to send a post request for any object. For that a DefaultHttpClient is used. HttpPost Object will take the url as the argument (only url not the parameters). The parameters you want to send can be edited above in BasicNameValuePair object. First parameter as the name of the parameter and second would be its value. As soon as you call the execute method the response will come in the HttpResponse Object. You now have to convert the HttpResponse object to Entity. And from Entity you can call EntityUtils.toString() method to convert to String. I suppose you're expecting a json data. You might have to map a class corresponding to it to convert json data to java class object.

我想你想为任何对象发送一个 post 请求。为此,使用了 DefaultHttpClient。HttpPost 对象将 url 作为参数(只有 url 不是参数)。您可以在上面的 BasicNameValuePair 对象中编辑要发送的参数。第一个参数作为参数的名称,第二个参数是它的值。只要您调用 execute 方法,响应就会出现在 HttpResponse 对象中。您现在必须将 HttpResponse 对象转换为实体。从 Entity 您可以调用 EntityUtils.toString() 方法来转换为 String。我想你在期待一个 json 数据。您可能必须映射与其对应的类才能将 json 数据转换为 java 类对象。