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