I am using Android Volley library to send POST request. And for POST request
Header is Content-Type:application/json
Post Body is Json String
But whatever,I do to change the Volley Request Header ,it is always set to Content-Type:text/html. And this gives me 400 Bad Request. Here is my class for do POST request on Volley
public class GsonRequest<T> extends Request<T> {
private final Class<T> clazz;
private final Map<String, String> headers;
private final Listener<T> listener;
private Map<String, String> postParams;
private String postString = null;
/**
* Make a GET request and return a parsed object from JSON.
*
* #param url
* URL of the request to make
* #param clazz
* Relevant class object, for Gson's reflection
* #param headers
* Map of request headers
*/
public GsonRequest(int method, String url, Class<T> clazz,
Map<String, String> headers, Map<String, Object> params,
Listener<T> listener, ErrorListener errorListener) {
super(method, url, errorListener);
this.clazz = clazz;
this.headers = headers;
this.listener = listener;
if (method == Method.POST && params != null && params.size() > 0) {
setRetryPolicy(new DefaultRetryPolicy(12000, 0,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
postString = new GsonBuilder().create().toJson(params);
}
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
return headers != null ? headers : super.getHeaders();
}
#Override
public byte[] getBody() throws AuthFailureError {
return postString != null ? postString.getBytes(Charset
.forName("UTF-8")) : super.getBody();
}
#Override
public String getBodyContentType() {
return postString !=null?"application/json; charset=utf-8":super.getBodyContentType();
}
#Override
protected void deliverResponse(T response) {
listener.onResponse(response);
}
#Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String json = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
Log.i("response", json);
T responses = new GsonBuilder().create().fromJson(json, clazz);
return Response.success(responses,
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JsonSyntaxException e) {
return Response.error(new ParseError(e));
} catch (Exception e) {
return Response.error(new ParseError(e));
}
}
}
Any idea what I am doing wrong.I have tested with normal HttpPost and it is working from there, but while using Volley,my POST Header is never changed.
I found I had to override getBodyContentType() in order to get the Content-Type header to update correctly:
public String getBodyContentType()
{
return "application/json; charset=utf-8";
}
Here is my question with some more details on this issue:
Volley Content-Type header not updating
Using network sniffing tool like Wireshark,I found that my error lay on wrong HTTP header. Then using Chrome DHC plugin
I found that Header Content-Type should be application/json; charset=utf-8and I was continuously using
Map<String, String> header = new HashMap<String, String>();
header.put("Content-Type", "application/json");
instead of
Map<String, String> header = new HashMap<String, String>();
header.put("Content-Type", "application/json; charset=utf-8");
Using proper Header solved my issue
Related
hello.
I want to make a post request using gson.
I got the class implemented into android website...
http://developer.android.com/intl/pt-br/training/volley/request-custom.html
UserRequestHelper.userRequest(Request.Method.POST, EndpointURL.USUARIO, null, new Response.Listener<Usuario>() {
#Override
public void onResponse(Usuario response) {
Toast.makeText(getActivity(), "Cadastro realizado com sucesso!", Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getActivity(), "Erro ao realizar cadastro.", Toast.LENGTH_SHORT).show();
}
});
I need a body to send the user? How i send the object user to make a post request?
Could someone help me with this?
you have to override getBody :
#Override
public byte[] getBody() throws AuthFailureError {
return gson.toJson(dataIn).getBytes();
}
the whole example class(form the same link) edited:
public class GsonRequest<T> extends Request<T> {
private final Gson gson = new Gson();
private final Class<T> clazz;
private final Map<String, String> headers;
private final Response.Listener<T> listener;
private final Object dataIn;
/**
* Make a GET request and return a parsed object from JSON.
*
* #param url URL of the request to make
* #param clazz Relevant class object, for Gson's reflection
* #param headers Map of request headers
*/
public GsonRequest(String url, Object dataIn, Class<T> clazz, Map<String, String> headers,
Response.Listener<T> listener, Response.ErrorListener errorListener) {
super(Method.POST, url, errorListener);
this.dataIn = dataIn;
this.clazz = clazz;
this.headers = headers;
this.listener = listener;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
return headers != null ? headers : super.getHeaders();
}
#Override
protected void deliverResponse(T response) {
listener.onResponse(response);
}
#Override
public byte[] getBody() throws AuthFailureError {
return gson.toJson(dataIn).getBytes();
}
#Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String json = new String(
response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(
gson.fromJson(json, clazz),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JsonSyntaxException e) {
return Response.error(new ParseError(e));
}
}
}
I am trying to hit a url to get the Json Response Previously I was using HTTPURLConnection and its working perfectly fine so I am updating from HttpUrlConnection to Volley
The url I am trying to hit is following
http://162.13.137.145:8073/api/PageContent/GetPageContentsByName?PageName=About Us
But With Volley I am unable to get response
I have made a custom Class extended from Request but I am having following issue
error: org.json.JSONEXception: Value Access of type java.lang.String cannot be converted to JSONObject
Code for Custom Class is following
public class CustomGetPostRequest extends Request<JSONObject> {
private int mMethod;
private String mUrl;
Map<String, String> mParams= new HashMap<String ,String>();
private Response.Listener<JSONObject> mListener;
HashMap<String, String> headers = new HashMap<String, String>();
public CustomGetPostRequest(int method, String url, Map<String, String> params,
Response.Listener<JSONObject> reponseListener, Response.ErrorListener errorListener) {
super(method, url, errorListener);
mMethod = method;
mUrl = url;
Log.d("Main URL",mUrl);
mParams = params;
mListener = reponseListener;
}
#Override
public String getUrl() {
if(mMethod == Request.Method.GET) {
StringBuilder stringBuilder = new StringBuilder(mUrl);
Iterator<Map.Entry<String, String>> iterator = mParams.entrySet().iterator();
int i = 1;
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
if(i == 1) {
stringBuilder.append("?" + entry.getKey() + "=" + entry.getValue());
} else {
stringBuilder.append("&" + entry.getKey() + "=" + entry.getValue());
}
iterator.remove(); // avoids a ConcurrentModificationException
i++;
}
mUrl = stringBuilder.toString();
Log.d("Converted URL",mUrl);
}
return mUrl;
}
#Override
protected Map<String, String> getParams()
throws com.android.volley.AuthFailureError {
Log.d("getParams","Called");
return mParams;
}
#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");
// headers.put ("Content-Type", "application/x-www-form-urlencoded");
return headers;
}
#Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(new JSONObject(jsonString),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JSONException je) {
if (response.statusCode == 200)// Added for 200 response
return Response.success(new JSONObject(),HttpHeaderParser.parseCacheHeaders(response));
else
return Response.error(new ParseError(je));
}
}
#Override
protected void deliverResponse(JSONObject response) {
// TODO Auto-generated method stub
mListener.onResponse(response);
}
}
I also come to know that for Request type Get getParam() is not called so changed the url and directly added params in url
request for the Volley is following
CustomGetPostRequest getPostRequest = new CustomGetPostRequest(Request.Method
.GET,cachedURL,params,this,this);
getPostRequest.setTag(ResponseTag.CONTENT_PAGES);
mQueue.add(getPostRequest);
What I am missing here?
The only issue that I was facing after long debug is url was pushed with space and was not recognized a proper url so i changed url from
http://162.13.137.145:8073/api/PageContent/GetPageContentsByName?PageName=About Us
to
http://162.13.137.145:8073/api/PageContent/GetPageContentsByName?PageName=About%20Us
and it worked
I am developing an Android app where I need to fetch results from a MySQL database in a remote server. I have written some PHP scripts to query the database and output the results in JSON format.
The problem is that the request fetches expected results only for the first time. When I send the same request with different POST params, it returns the first result all over again. I modified the PHP script to attach the POST param in the JSON result and tried logging the POST param. It is also the same first param.
If I uninstall the app from the device and re-install, again it returns the correct JSON only for the first time.
NOTE: When i run the same code with the same PHP scripts and same database on localhost (WAMPP), everything works perfect.
I tried using the Google Chrome extension Postman to check the output from the remote server, it worked as expected. So, I can confirm that the problem is with my app/code.
Here's my CustomJSONObjectRequest class :
public class CustomJSONObjectRequest extends Request<JSONObject> {
private Listener<JSONObject> listener;
private Map<String, String> params;
public CustomJSONObjectRequest(String url, Map<String, String> params,
Listener<JSONObject> reponseListener, ErrorListener errorListener) {
super(Method.GET, url, errorListener);
this.listener = reponseListener;
this.params = params;
}
public CustomJSONObjectRequest(int method, String url, Map<String, String> params,
Listener<JSONObject> reponseListener, ErrorListener errorListener) {
super(method, url, errorListener);
this.listener = reponseListener;
this.params = params;
}
protected Map<String, String> getParams()
throws com.android.volley.AuthFailureError {
return params;
};
#Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(new JSONObject(jsonString),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JSONException je) {
return Response.error(new ParseError(je));
}
}
#Override
protected void deliverResponse(JSONObject response) {
listener.onResponse(response);
}
}
And this is how I am sending the request :
String item_name = getIntent().getExtras().getString("item_name");
String url = getString(R.string.remote_server)+"fetch-item-list.php";
CustomJSONObjectRequest jsObjRequest = new CustomJSONObjectRequest(Request.Method.POST, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
Log.d("item name from intent extra", item_name); //intent extra
Log.d("response", response.toString()); //json response
Log.d("item name from response", response.getString("item_name")); //post parameter. This and the intent extra should be same
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getApplicationContext(), error.toString(), Toast.LENGTH_SHORT).show();
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.put("item_name", item_name);
return params;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> header = new HashMap<String, String>();
header.put("Content-Type", "application/json; charset=utf-8");
return header;
}
};
MyVolleySingleton.getInstance(getApplicationContext()).addToRequestQueue(jsObjRequest);
This is the logcat :
D/item name from intent extra: apple
D/Response: {"data":[{"item_discount":"0.00","item_price":"50.00","unique_id":"181................
D/item name from response: orange
I think I found the solution
Looks like the JSON response was getting cached, so the response for the first request got cached and the next requests were never sent to the server. The cached JSON response was returned for every other requests.
All I had to do was disable caching.
I added the line jsObjRequest.setShouldCache(false); before adding it to the request queue.
jsObjRequest.setShouldCache(false);
MyVolleySingleton.getInstance(getApplicationContext()).addToRequestQueue(jsObjRequest);
Thanks to this question.
But I still do not get it why it worked on localhost without this setting.
I am using volley for simple REST request and passing some post parameters in it. But It always giving response BasicNetwork.performRequest: Unexpected response code 400.
I have tried following custom request.
public class GsonRequestRest<T> extends Request<T>{
private static final String PROTOCOL_CHARSET = "utf-8";
private static final String PROTOCOL_CONTENT_TYPE = String.format("application/json; charset=%s", PROTOCOL_CHARSET);
private final Listener<T> mListener;
private final String mRequestBody;
private Gson mGson;
private Class<T> mJavaClass;
private Map<String, String> params;
public GsonRequestLoginRest(int method, String url, Class<T> cls, String requestBody, Map<String, String> params,Listener<T> listener,ErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
mJavaClass = cls;
mListener = listener;
mRequestBody = requestBody;
this.params = params;
}
#Override
protected Map<String, String> getParams() throws com.android.volley.AuthFailureError {
return params;
};
#Override
protected void deliverResponse(T response) {
mListener.onResponse(response);
}
private Map<String, String> headers = new HashMap<String, String>();
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
return headers;
}
#Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
T parsedGSON = mGson.fromJson(jsonString, mJavaClass);
return Response.success(parsedGSON,HttpHeaderParser.parseCacheHeaders(response));
} catch (IOException e) {
Log.d("tag", e.getMessage());
return Response.error(new ParseError(e));
} catch (JsonSyntaxException je) {
return Response.error(new ParseError(je));
}
}
#Override
public String getBodyContentType() {
return PROTOCOL_CONTENT_TYPE;
}
#Override
public byte[] getBody() {
try {
return mRequestBody == null ? null : mRequestBody.getBytes(PROTOCOL_CHARSET);
} catch (UnsupportedEncodingException uee) {
VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s",mRequestBody, PROTOCOL_CHARSET);
return null;
}
}
//In your extended request class
#Override
protected VolleyError parseNetworkError(VolleyError volleyError){
if(volleyError.networkResponse != null && volleyError.networkResponse.data != null){
VolleyError error = new VolleyError(new String(volleyError.networkResponse.data));
volleyError = error;
}
return volleyError;
}
}
I did try to override getParams() and pass parameters in it. But it was not passing parameters and throwing error 400. I tried many of suggestions here and here but nothing worked for me. Is there any bug in Volley. ?
Please guide.
it working for me when use getBody() instead of getParams() in Request class.
another thing you should use JSONObject instead of HashMap
to put your params
.
then convert the JSONObject to string and convert string to byte in the getBody method.
use this link for more explanation.
How to send a POST request using volley with string body?
Hope my answer clarified enough to you.
I am currently using GsonRequest to issue rest GET requests. Not clear on what to use for PUT requests where I need to send over a whole JSon object to be updated. The Request object will accept PUT but I'm not sure how place the JSon object that is expected.
Here is my json to be PUT:
{
prop1 : true,
prop2 : false,
prop4 : true
}
Here is how its submitted in apiary.io for example:
var xhr = new XMLHttpRequest();
xhr.open('PUT', 'http://my.apiary.io/v1/records/{myid}.json');
xhr.send("{\n \"isEditable\": false,\n \"isClosed\": true,\n \"isAvail\": true\n}");
I don't know where to put the JSON.
Thanks
public class GsonRequest<T> extends Request<T> {
private final Gson gson ;
private final Class<T> clazz;
private final Map<String, String> headers;
private final Listener<T> listener;
public GsonRequest(int method, String url, Class<T> clazz, Map<String, String> headers,
Listener<T> listener, ErrorListener errorListener) {
super(method, url, errorListener);
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Timestamp.class, new TimestampDeserializer());
this.gson = gsonBuilder.create();
this.clazz = clazz;
this.headers = headers;
this.listener = listener;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
return headers != null ? headers : super.getHeaders();
}
#Override
protected void deliverResponse(T response) {
listener.onResponse(response);
}
#Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String json = new String(
response.data, HttpHeaderParser.parseCharset(response.headers));
return Response.success(
gson.fromJson(json, clazz), HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JsonSyntaxException e) {
return Response.error(new ParseError(e));
}
}
}
And here are the base getBody methods inside the request. It seems to handle parameters on the Method.PUT, but what if its a JSON string that needs to be sent in the body?
/**
* Returns the raw POST or PUT body to be sent.
*
* #throws AuthFailureError in the event of auth failure
*/
public byte[] getBody() throws AuthFailureError {
Map<String, String> params = getParams();
if (params != null && params.size() > 0) {
return encodeParameters(params, getParamsEncoding());
}
return null;
}
/**
* Converts <code>params</code> into an application/x-www-form-urlencoded encoded string.
*/
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);
}
}
Suggested solution:
// add a Json body.
public String jsonBody;
/**
* Returns the raw POST or PUT body to be sent.
*
* #throws AuthFailureError in the event of auth failure
*/
public byte[] getBody() throws AuthFailureError {
if ((getMethod() == Method.PUT) && (jsonBody != null))
{
return jsonBody.getBytes(); // Encoding required?????
}
else
{
return super.getBody();
}
}
The abstract base class Request has a constructor which takes a Request.Method as the first parameter. All the Request implementations in volley.toolbox also have a constructor like that as well.
I'm not sure where GsonRequest is coming from but if it doesn't have a constructor which takes a Method, you can add one yourself.
Edit: You can override getBody and getBodyContentType to return the custom request body and MIME type respectively.
I know this is a quite old topic but i had to adapt the suggested solution to make it work for me, so i though the same approach could work for others:
I had to add some headers to the getHeaders function:
/**
* Passing some request headers
* */
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json");
headers.put("Accept", "*/*");
return headers;
}
Then i was able to use the suggested solution with getBody()
#Override
/**
* Returns the raw POST or PUT body to be sent.
*
* #throws AuthFailureError in the event of auth failure
*/
public byte[] getBody() throws AuthFailureError {
String jsonBody = "{\"status\":\"true"}";
if ((getMethod() == Method.PUT) && (jsonBody != null)){
return jsonBody.getBytes();
}else{
return super.getBody();
}
}