Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring RestTemplate HTTP Post with parameters cause 400 bad request error

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

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:

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.

like image 605
ductran Avatar asked Apr 03 '14 02:04

ductran


2 Answers

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 -F parameter which specifies multipart post data:

-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:

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.

like image 58
Roy Clarkson Avatar answered Oct 15 '22 23:10

Roy Clarkson


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.

like image 2
Aarambh Avatar answered Oct 15 '22 23:10

Aarambh