user4071017
user4071017

Reputation: 461

Send form-urlencoded parameters in post request android volley

I want to make a POST JSONObjectRequest with form urlencoded parameters. How can I do this? I've tried the following code, but to no avail.

final String api = "http://api.url";
final JSONObject jobj = new JSONObject();
jobj.put("Username", "usr");
jobj.put("Password", "passwd");
jobj.put("grant_type", "password");

final JsonObjectRequest jor = new JsonObjectRequest(

    Request.Method.POST, 
    api, jobj, 
    new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {
            Toast.makeText(getApplicationContext(), "Login Successful!", Toast.LENGTH_LONG).show();
            //do other things with the received JSONObject
        }
    }, 
    new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Toast.makeText(getApplicationContext(), "Error!", Toast.LENGTH_LONG).show();
        }
    }) {

    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        Map<String, String> pars = new HashMap<String, String>();
        pars.put("Content-Type", "application/x-www-form-urlencoded");
        return pars;
    }
};

//add to the request queue
requestqueue.AddToRequestQueue(jor);

I'm getting a 400 bad request with the api call! How can I fix it?

Upvotes: 46

Views: 44865

Answers (8)

bayram.cicek
bayram.cicek

Reputation: 333

I was looking for answers in Kotlin language. Send x-www-form-urlencoded parameters in post request with android volley in Kotlin language:

    val queue = Volley.newRequestQueue(this)

    val stringRequest: StringRequest = object : StringRequest(
        Method.POST,
        link,
        Response.Listener { response ->
            Log.i("response:", response)
        },

        Response.ErrorListener { error ->
            Log.i("response error:", "$error")
            error.printStackTrace()
        }) {
        override fun getBodyContentType(): String {
            return "application/x-www-form-urlencoded"
        }

        override fun getHeaders(): Map<String, String> {
            val headers: MutableMap<String, String> =
                HashMap()
            headers["Content-Type"] = "application/x-www-form-urlencoded"
            headers["Accept"] = "application/json"
            return headers
        }

        @Throws(AuthFailureError::class)
        override fun getParams(): Map<String, String> {
            val params: MutableMap<String, String> =
                HashMap()
            params["value1"] = "value1"
            params["value2"] = "value2"
            return params
        }
    }

    queue.add(stringRequest)

Upvotes: 1

Bala Vishnu
Bala Vishnu

Reputation: 2628

Ater a long long struggle, found the solution. You need to override getBodyContentType() and return application/x-www-form-urlencoded; charset=UTF-8.

StringRequest jsonObjRequest = new StringRequest(

    Request.Method.POST,
    getResources().getString(R.string.base_url),
    new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {

            MyFunctions.toastShort(LoginActivity.this, response);
        }
    }, 
    new Response.ErrorListener() {

        @Override
        public void onErrorResponse(VolleyError error) {
            VolleyLog.d("volley", "Error: " + error.getMessage());
            error.printStackTrace();
            MyFunctions.croutonAlert(LoginActivity.this,
                MyFunctions.parseVolleyError(error));
            loading.setVisibility(View.GONE);
        }
    }) {

    @Override
    public String getBodyContentType() {
        return "application/x-www-form-urlencoded; charset=UTF-8";
    }

    @Override
    protected Map<String, String> getParams() throws AuthFailureError {
        Map<String, String> params = new HashMap<String, String>();
        params.put("username", etUname.getText().toString().trim());
        params.put("password", etPass.getText().toString().trim());
        return params;
    }

};

AppController.getInstance().addToRequestQueue(jsonObjRequest);

Upvotes: 90

Prabin Shrestha
Prabin Shrestha

Reputation: 1

public void sendUserRegistrationRequest(final UserRequest userRequest, final ResponseListener responseListener) {
    String url = Api.POST_NRNA_REGISTRATION;

    StringRequest userRegistrationRequest = new StringRequest(Request.Method.POST, url, new com.android.volley.Response.Listener<String>() {
        @Override
        public void onResponse(String response) {

            JSONObject jsonObject = GsonUtils.getJSONObject(response);
            LoggerUtils.log(TAG, "" + jsonObject.toString());

        }
    }, new com.android.volley.Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            LoggerUtils.log(TAG, GsonUtils.toString(error));
            responseListener.onError(GsonUtils.toString(error));
        }
    }) {

        //use this if you have to use form posting : for application/x-www-form-urlencoded;
        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            return GsonUtils.getHashMap(userRequest);
        }

        @Override
        public String getBodyContentType() {
            return "application/x-www-form-urlencoded; charset=UTF-8";
        }


    };
    VolleyRequestQueue.getInstance(context).addToRequestQueue(userRegistrationRequest);
}

Use this if you have to send like "application/json"

        @Override
        public byte[] getBody() throws AuthFailureError {
            String jsonData = GsonUtils.toString(userRequest);
            return jsonData.getBytes();
        }

        @Override
        public String getBodyContentType() {
            return "application/json";
        }




public class GsonUtils {

public static String TAG = GsonUtils.class.getSimpleName();

public static <T> T toObject(String data, Class<T> type) {
    Gson gson = new Gson();
    return gson.fromJson(data, type);
}

public static String toString(Object src) {
    if (src == null) {
        return null;
    }
    GsonBuilder builder = new GsonBuilder();
    builder.setPrettyPrinting();
    Gson gson = builder.create();
    return gson.toJson(src);
}


public static <T> T toObject(String data, Type type) {
    try {
        Gson gson = new Gson();
        return gson.fromJson(data, type);
    } catch (Exception ex) {
        Timber.v(ex.getMessage());
        return null;
    }
}


public static JSONObject getJSONObject(Object src) {
    String data = toString(src);
    LoggerUtils.log(TAG, data);
    try {
        return new JSONObject(data);
    } catch (JSONException e) {
        LoggerUtils.log(TAG, e.getMessage());
    }
    return null;
}


public static JSONObject getJSONObject(String data) {
    try {
        return new JSONObject(data);
    } catch (JSONException e) {
        LoggerUtils.log(TAG, e.getMessage());
    }
    return null;
}


public static HashMap<String, String> getHashMap(Object src) {
    String data = toString(src);
    LoggerUtils.log(TAG, data);
    return toObject(data, new TypeToken<HashMap<String, String>>() {
    }.getType());
}

}

Upvotes: 0

Akeshwar Jha
Akeshwar Jha

Reputation: 4576

I did it the following way (the content-type of my request-body was application/x-www-form-urlencoded):

I've commented at appropriate places in the code.

/**
     * @param url - endpoint url of the call
     * @param requestBody - I'm receiving it in json, without any encoding from respective activities.
     * @param listener - StringRequestListener is an Interface I created to handle the results in respective activities
     * @param activity - just for the context, skippable.
     * @param header - This contains my x-api-key
     */
    public void makePostRequest2(String url, final JSONObject requestBody, final StringRequestListener listener,
                                 Activity activity, final Map<String,String> header) {

        RequestQueue queue = VolleySingleton.getInstance().getRequestQueue();

        /**
         * You can skip this network testing.
         */
        if(!NetworkTester.isNetworkAvailable()) {
            Toast.makeText(MyApplication.getAppContext(),"Network error",Toast.LENGTH_SHORT).show();
            return;
        }


        StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                listener.onResponse(response);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                listener.onError(error);
            }
        }) {
            /**
             * Setting the body-content type is the most important part.
             * @return
             * You don't have to write this method if your body content-type is application/x-www-form-urlencoded and encoding is charset=UTF-8
             * Because the base method is does the exact same thing.
             */
//            @Override
//            public String getBodyContentType() {
//                return "application/x-www-form-urlencoded; charset=UTF-8";
//            }


            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                return header;
            }


            /**
             * I have copied the style of this method from its original method from com.Android.Volley.Request
             * @return
             * @throws AuthFailureError
             */
            @Override
            public byte[] getBody() throws AuthFailureError {

                Map<String, String> params = new HashMap<>();
                try {
                    params.put("grant_type","password");
                    params.put("username",requestBody.getString("username"));
                    params.put("password",requestBody.getString("password"));
                } catch (JSONException e) {
                    e.printStackTrace();
                }

                //yeah, I copied this from the base method. 
                if (params != null && params.size() > 0) {
                    return encodeParameters(params, getParamsEncoding());
                }
                return null;


            }

        };

        queue.add(stringRequest);

    }

    /**
     * This method was private in the com.Android.Volley.Request class. I had to copy it here so as to encode my paramters.
     * @param params
     * @param paramsEncoding
     * @return
     */
    private byte[] encodeParameters(Map<String, String> params, String paramsEncoding) {
        StringBuilder encodedParams = new StringBuilder();
        try {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                encodedParams.append(URLEncoder.encode(entry.getKey(), paramsEncoding));
                encodedParams.append('=');
                encodedParams.append(URLEncoder.encode(entry.getValue(), paramsEncoding));
                encodedParams.append('&');
            }
            return encodedParams.toString().getBytes(paramsEncoding);
        } catch (UnsupportedEncodingException uee) {
            throw new RuntimeException("Encoding not supported: " + paramsEncoding, uee);
        }
    }

Upvotes: 3

shakrlabs.com
shakrlabs.com

Reputation: 61

Volley adds a Content-Type header right before the request is sent out.

     /**
     * Returns the content type of the POST or PUT body.
     */
     public String getBodyContentType() {
         return "application/x-www-form-urlencoded; charset=" + getParamsEncoding();
      }

You must override this with a custom request object.

    public class CustomVolleyRequest extends StringRequest {
           ...

           @Override
           public String getBodyContentType() {
                return "application/json";
           }               

           ...
    }

Upvotes: 2

TheOne_su
TheOne_su

Reputation: 747

public static void DoPostStringResult(String url, Object Tag,
        final StringCallBack CallBack, Context context,
        final String body) {
    StringRequest request = new StringRequest(Request.Method.POST, url,
            new Listener<String>() {

                @Override
                public void onResponse(String result) {
                    CallBack.getResult(result);
                }

            }, new ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    CallBack.getError(error);
                }

            }) {
        // @Override
        // public Map<String, String> getHeaders() throws AuthFailureError {
        // //设置头信息
        // Map<String, String> map = new HashMap<String, String>();
        // map.put("Content-Type", "application/x-www-form-urldecoded");
        // return map;
        // }

        @Override
        public byte[] getBody() throws AuthFailureError {
            // TODO Auto-generated method stub
            return body.getBytes();
        }

        @Override
        public String getBodyContentType() {
            // TODO Auto-generated method stub
            return "application/x-www-form-urlencoded";
        }

        /**
         * 设置Volley网络请求的编码方式。。。。
         */
        @Override
        protected String getParamsEncoding() {
            return "utf-8";
        }

    };

    request.setRetryPolicy(new DefaultRetryPolicy(30 * 1000,
            DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
            DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));

    request.setTag(Tag);
    VolleyUtils.getRequestQueue(context).add(request);
}

and your body must be like this "username=aa&password=bb&[email protected]"

Upvotes: 9

CQM
CQM

Reputation: 44228

There is no premade constructor in JsonObjectRequest that accepts post parameters, so you made your own constructor

You have to both assign your Map to an already declared variable in that method within your constructor, and you also have to add this method

@Override
protected Map<String, String> getParams() throws AuthFailureError {
    return this.params;
}

Upvotes: 0

mmlooloo
mmlooloo

Reputation: 18977

try using StringRequest like below code:

final String api = "http://api.url";
final StringRequest stringReq = new StringRequest(Request.Method.POST, api, new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject response) {
                    Toast.makeText(getApplicationContext(), "Login Successful!", Toast.LENGTH_LONG).show();
  //do other things with the received JSONObject
                }
            }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    Toast.makeText(getApplicationContext(), "Error!", Toast.LENGTH_LONG).show();
               }
            }) {
                @Override
                public Map<String, String> getHeaders() throws AuthFailureError {
                    Map<String, String> pars = new HashMap<String, String>();
                    pars.put("Content-Type", "application/x-www-form-urlencoded");
                    return pars;
                }

                @Override
                public Map<String, String> getParams() throws AuthFailureError {
                    Map<String, String> pars = new HashMap<String, String>();
                    pars.put("Username", "usr");
                    pars.put("Password", "passwd");
                    pars.put("grant_type", "password");
                    return pars;
                }
            };
  //add to the request queue
  requestqueue.AddToRequestQueue(stringReq);

Upvotes: 5

Related Questions