22

I'm trying to make a POST request to my API and it works in Postman (I get a valid JSON object), but not using Volley. With the following code:

String URL = "http://somename/token";
RequestQueue queue = Volley.newRequestQueue(StartActivity.this);
queue.add(new JsonObjectRequest(Method.POST, URL, null,
   new Listener<JSONObject>() {
       @Override
       public void onResponse(JSONObject response) {
           // handle response
           Log.i("StartActivity", response.toString());
       }
   }, new ErrorListener() {
       @Override
       public void onErrorResponse(VolleyError error) {
           // handle error   
           Log.i("StartActivity", error.toString());
       }
   }) {

   @Override
   public Map<String, String> getHeaders() throws AuthFailureError {
       HashMap<String, String> headers = new HashMap<String, String>();
       headers.put("username", "someUsername");
       headers.put("password", "somePassword");
       headers.put("Authorization", "Basic someCodeHere");
       return headers;
   }
   @Override
    protected Map<String,String> getParams(){
        Map<String,String> params = new HashMap<String, String>();
        params.put("grant_type", "client_credentials");

            return params;
        }
   });

I get the following error:

02-12 21:42:54.774: E/Volley(19215): [46574] BasicNetwork.performRequest: Unexpected response code 400 for http://somename/token/

I have seen a lot of examples and I don't really see what is going wrong here. Anyone any idea?

I updated the code with this method:

HashMap<String, String> createBasicAuthHeader(String username, String password) {
        HashMap<String, String> headerMap = new HashMap<String, String>();

        String credentials = username + ":" + password;
        String base64EncodedCredentials =
                Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
        headerMap.put("Authorization", "Basic " + base64EncodedCredentials);

        return headerMap;
    }

and changed getHeaders() to:

@Override
   public Map<String, String> getHeaders() throws AuthFailureError {
       return createBasicAuthHeader("username", "password");
   }

Still getting the same error!

Loolooii
  • 8,588
  • 14
  • 66
  • 90
  • are you sure you're putting in the auth headers correctly? if you're using basic auth you should be base64 encoding the username:password I believe – panini Feb 12 '14 at 20:54
  • @panini I'm already setting the base64 code as "somecodehere". – Loolooii Feb 12 '14 at 21:16
  • @just8laze I'm just using Android's AsyncTask. It's much simpler and it works perfect. See this thread: http://stackoverflow.com/questions/9671546/asynctask-android-example – Loolooii May 19 '14 at 11:53
  • @Loolooii Yeah, I already have it working with AsyncTask and HttpPost. No idea why it doesn't work with Volley. Thanks for the response. – Robby Smet May 19 '14 at 11:56
  • @just8laze I'm glad that worked for you and you're welcome. – Loolooii May 19 '14 at 12:00
  • @Loolooii: Have you solved this issue? I am also facing the exact same problem. It will be helpful if you can explain how you solved this issue. Thanks. – roy mathew May 20 '15 at 17:32
  • @roymathew I ended up using AsyncTask class, but if you want a library you can use this: http://loopj.com/android-async-http/. Honestly I haven't tried to use Volley anymore. – Loolooii May 24 '15 at 20:24
  • Carefully check your JSON request. In my case, it was malformed, hence the error. – Sevastyan Savanyuk Apr 17 '18 at 13:15

12 Answers12

23

I had the same problem and i removed from the header:

  headers.put("Content-Type", "application/json");

now it works great!

  • 1
    Waoooo... awesome... its great – Muhammad Zahab Dec 29 '16 at 15:09
  • Most of the time passing content type in headers wouldn't work, So you must need to override this method to declare the content type: `getBodyContentType()` – Moosa Baloch Aug 24 '18 at 19:13
  • I was facing issue of 400-Bad request reason I was sending "content-Type" ,"application/json" in headers so this issue resolved by removing content type from headers. – user1912026 Sep 25 '19 at 07:49
9

If you are passing the json value to in body(raw json).No need to set the content type as headers.put("Content-Type", "application/json; charset=utf-8");

When I was using the content type in header callback ,the 400 response status I was getting in logcat.I commented headers.put("Content-Type", "application/json; charset=utf-8"); as because I am passing raw json in body while calling api.screenshot for postman is attached.It will help

private void volleyCall(String email, String password) {

      RequestQueue queue= Volley.newRequestQueue(this);
      String URL = "http://XXXX.in:8080/XXXX/api/userService/login";

      Map<String, String> jsonParams = new HashMap<String, String>();
      jsonParams.put("email", email);
      jsonParams.put("password", password);
      Log.d(TAG,"Json:"+ new JSONObject(jsonParams));

      JsonObjectRequest postRequest = new JsonObjectRequest( Request.Method.POST, URL,new JSONObject(jsonParams),
              new Response.Listener<JSONObject>() {
                  @Override
                  public void onResponse(JSONObject response) {
                      Log.d(TAG,"Json"+ response);
                  }
              },
              new Response.ErrorListener() {
                  @Override
                  public void onErrorResponse(VolleyError error) {
                      //   Handle Error
                      Log.d(TAG, "Error: " + error
                              + "\nStatus Code " + error.networkResponse.statusCode
                              + "\nResponse Data " + error.networkResponse.data
                              + "\nCause " + error.getCause()
                              + "\nmessage" + error.getMessage());
                  }
              }) {
          @Override
          public Map<String, String> getHeaders() throws AuthFailureError {
              HashMap<String, String> headers = new HashMap<String,String>();
             // headers.put("Content-Type", "application/json; charset=utf-8");
              return headers;
          }
          @Override
          public String getBodyContentType() {
              return "application/json";
          }



      };

      queue.add(postRequest);

  }

LogCat:
LoginActivity: Json:{"email":"XXXXXX@gmail.com","password":"abcde"}
LoginActivity: Error: com.android.volley.ServerError
                                                                          
Status Code 400                                                                     
Response Data [B@63ca992                                                                              
Cause null                                                                              
messagenull

dev.doc
  • 569
  • 3
  • 12
  • 18
Priyanshu Singh
  • 704
  • 8
  • 12
  • thanks that's exactly what was happening with me, your answer saved me from hours of head scratching. – Raaf003 Apr 06 '18 at 10:12
  • i got same thing as u but how to manage to get the response from server and not [B@63ca992 –  Jun 27 '18 at 10:37
6

There can be multiple reasons for this error.

One reason, of course, as said by others, is that maybe you are missing or have improperly set 'Content-type' header.

If you have properly implemented that, another possible reason is that you are sending params directly from your URL. There may be a case when params is a string with some white spaces in it. These white spaces cause problems in GET requests through Volley. You need to find another way around it. That's all.

Pang
  • 9,564
  • 146
  • 81
  • 122
Rohit
  • 475
  • 4
  • 18
  • 1
    This does not provide an answer to the question. Once you have sufficient [reputation](http://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](http://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](http://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/low-quality-posts/11974307) – silwar Apr 11 '16 at 12:43
  • 1
    This answer worked for me. That is why I posted it here. – Rohit Apr 11 '16 at 15:46
  • 1
    This answer is very helpful. The get request url-with-space problem is very tricky. Very thanks for your suggestion – Pranithan T. May 13 '18 at 16:34
4

400 error is because Content-Type is set wrong. Please do the following.

  1. GetHeader function should be as

        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
    
            Map<String, String> param = new HashMap<String, String>();
    
            return param;
        }
    
  2. Add this new override function.

        @Override
        public String getBodyContentType() {
            return "application/json";
        }
    
Kashi
  • 234
  • 2
  • 5
  • After spending a couple of hours on this, it is very important that the getHeaders()-method does NOT contain a "Content-Type" header, aside from having to add the getBodyContentType()-method, that is the most important part of this answer. Other headers can be present in the getHeaders()-method however. – Kenneth Saey Jan 19 '18 at 15:02
3

400 indicates a bad request, maybe you're missing Content-Type=application/json on your headers

Leonardo Pinto
  • 309
  • 3
  • 7
  • 3
    it's something else, `JsonRequest` has that by default – thepoosh Feb 12 '14 at 21:03
  • I think @thepoosh is right, anyway I tried it and still getting the same error. – Loolooii Feb 12 '14 at 21:16
  • @thepoosh its not a server error, its a bad request which means if anything its a client error – panini Feb 12 '14 at 21:20
  • I meant to say, server initiated error, meaning the API was misused – thepoosh Feb 12 '14 at 21:23
  • @panini I checked the logs and there's nothing. I do the exact same thing in Postman and it works. – Loolooii Feb 12 '14 at 21:28
  • @Loolooii do you have access to the server? I would suggest checking to see if the request does actually match the one seen in Postman. If you don't have access to it, then [mitmproxy](https://github.com/mitmproxy/mitmproxy) is good for checking requests. I get the feeling that the request being sent from Volley won't match the Postman one – panini Feb 12 '14 at 21:31
  • @panini yes I have, it's hosted on Heroku and I just checked the logs. There's no problem at all. – Loolooii Feb 12 '14 at 21:45
  • @Loolooii, have you tried `Accept=application/json`? – Leonardo Pinto Feb 13 '14 at 16:39
  • @LeonardoPinto I get a TimeoutError. Do you know how I can fix that? – Loolooii Feb 14 '14 at 12:19
1

I have the same issue before and I got the solution in my project:

RequestQueue requestManager = Volley.newRequestQueue(this);

        String requestURL = "http://www.mywebsite.org";
        Listener<String> jsonListerner = new Response.Listener<String>() {
            @Override
            public void onResponse(String list) {

            }
        };

        ErrorListener errorListener = new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.w("Volley Error", error.getMessage());
            }
        };

        StringRequest fileRequest = new StringRequest(Request.Method.POST, requestURL, jsonListerner,errorListener){
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                Map<String,String> params = new HashMap<String, String>();
                params.put("token", account.getToken());
                return params;
            }

            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                HashMap<String, String> headers = new HashMap<String, String>();
                // do not add anything here
                return headers;
            }
        };
        requestManager.add(fileRequest);

In the code Snippet above I used Post Method:

My answer is base on my experience and so take note:

1.) When using POST method use "StringRequest" instead of "JsonObjectRequest"

2.) inside getHeaders Override the value with an Empty HashMap

 example snippet:

        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            Map<String,String> params = new HashMap<String, String>();
            params.put("token", account.getToken());
            return params;
        }

        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            HashMap<String, String> headers = new HashMap<String, String>();
            // do not add anything here
            return headers;
        }

And everything works in my case.

neferpitou
  • 1,642
  • 2
  • 20
  • 26
1

I've got this error and now Iit's been fixed. I did what is told in this link. What you need to do is

  1. go to src/com/android/volley/toolbox/BasicNetwork.java
  2. Change the following lines
 if (statusCode < 200 || statusCode > 299) {
     throw new IOException();
 }

with

 if (statusCode < 200 || statusCode > 405) {
     throw new IOException();
 }

Hope this helps.

Community
  • 1
  • 1
stackex
  • 3,205
  • 1
  • 11
  • 16
0

I have removed this params.put("Content-Type", "application/x-www-form-urlencoded");

This is my Code Change.

@Override
        protected Map<String,String> getParams(){
            Map<String,String> params = new HashMap<String, String>();
            if(!isLogout) {
                params.put("username", username);
                params.put("password", password);
                params.put("grant_type", "password");
            } else {
            }
            return params;
        }

        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            Map<String,String> params = new HashMap<String, String>();
            if(isLogout) {
                params.put("Authorization", "bearer "+LibraryDataModel.getToken());
            }else {
            // Removed this line
            // params.put("Content-Type", "application/x-www-form-urlencoded");
            }
            return params;
        }
dhiku
  • 1,818
  • 2
  • 22
  • 38
0

In Android 2.3 there is a problem using Base64.encodeToString() as it introduces a new line in HTTP header. See my response to this question here in SO.

Short answer: Don't use Base64.encodeToString() but put the already encoded String there.

Community
  • 1
  • 1
Raul Pinto
  • 1,095
  • 8
  • 15
0

I have find a solution if you are using postman for hitting the api and your api have defined serializer field like skill = serializers.JSONField() then that type of error occurred-

Solution For POSTMAN- you just add binary=True inside JSONField ex- skill = serializers.JSONField(binary=True)

Solution for Android or other client then- you just remove binary=True inside JSONField ex- skill = serializers.JSONField()

0

Somertimes this error 400 is arise due to Request type so you need to change the Request.Method.GET to Request.Method.POST and than it works like a charm.

Dhruv Tyagi
  • 814
  • 1
  • 9
  • 28
-1

Check if you are using correct SDK

For Android Studio / IntelliJIDEA:

File -> Project Structure -> Project -> Project SDK 
Modules -> Check each modules "Module SDK" 

Preferably, you should use "Google API (x.x)" instead of Android API

tausiq
  • 937
  • 1
  • 13
  • 23