In my Android application, I am using google's volley for network operations. There is a case where I need to make a request but send body as form-data.
I have tried everything else, but I am not able to make the request as form-data.
Here is a curl
curl -X POST -H "Content-Type: multipart/form-data" -F "mobile_number=<XXXX>" "<server_url>"
How can I achieve that -F part in volley? The Server is throwing bad request.
This is what I have done :
final JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.POST, URLFactory.OTP_URL,
null, listener, errorListener){
#Override
public byte[] getBody() {
final JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("mobile_number", mobileNumber);
} catch (JSONException e) {
e.printStackTrace();
return null;
}
return jsonObject.toString().getBytes();
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
final HashMap<String, String> headers = new HashMap<>();
headers.put("Content-Type", "multipart/form-data");
return headers;
}
};
Please help me in this.
This can be done in volley by creating the postBody yourself. Please refer the below code.
Code for creating the body:
private String createPostBody(Map<String, String> params) {
StringBuilder sbPost = new StringBuilder();
for (String key : params.keySet()) {
if (params.get(key) != null) {
sbPost.append("\r\n" + "--" + BOUNDARY + "\r\n");
sbPost.append("Content-Disposition: form-data; name=\"" + key + "\"" + "\r\n\r\n");
sbPost.append(params.get(key));
}
}
return sbPost.toString();
}
Modifed getBody() code :
#Override
public byte[] getBody() {
Map<String,String> params = new HashMap<>();
params.add("mobile_number", mobileNumber);
String postBody = createPostBody(params);
return postBody.getBytes();
}
You will need to modify getHeaders as well to tell the server what you boundary is :
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
final HashMap<String, String> headers = new HashMap<>();
headers.put("Content-Type", "multipart/form-data;boundary=" + BOUNDARY;);
return headers;
}
Related
I'm trying to produce a proper request for Twitter Application-only authorization token using a Volley POST request, but I keep getting a Http 400 response (Bad Request).
This is what I tried :
URL
private static final String TWITTER_API_AUTH_URL = "https://api.twitter.com/oauth2/token";
Encoding the consumer key and the consumer secret
try {
byte[] data = (URLEncoder.encode(TWITTER_CONSUMER_KEY, "UTF-8") + ":" + URLEncoder.encode(TWITTER_CONSUMER_SECRET, "UTF-8")).getBytes("UTF-8");
mEncodedKeyAndSecret = Base64.encodeToString(data, Base64.DEFAULT);
} catch (UnsupportedEncodingException e) {
//handleError
}
Custom Volley StringRequest
private class TokenRequestWithAuthHeader extends StringRequest{
public TokenRequestWithAuthHeader (int method, String url, Response.Listener listener, Response.ErrorListener errorListener)
{
super(method, url, listener, errorListener);
}
#Override
public Map getHeaders() throws AuthFailureError {
Map headers = new HashMap();
headers.put("Content-Length", String.valueOf(getBody().length));
headers.put("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
headers.put("Authorization", "Basic " + mEncodedKeyAndSecret);
return headers;
}
#Override
public byte[] getBody() {
return ("grant_type=client_credentials").getBytes();
}
}
Sending Request
tokenRequest = new TokenRequestWithAuthHeader
(Request.Method.POST, TWITTER_API_AUTH_URL, mCallback.getTokenResponseListener(), mCallback);
requestQueue.add(tokenRequest);
Documentation about Application-Only authentication at dev.twitter.com
I also tried extending JsonObjectRequest and JsonRequest instead of StringRequest, same result.
Can someone help identify what is the problem with the request ?
I have just tested with the credential you've provided in comments. It's working with the following logcat output (I truncated real access token's content)
I/onResponse: {"access_token":"AAAAAAAAAAAAAAAAAAAAAIwbjgAAAAAAGVMKCDU9taD0ke3sStAyA2WKszs%3DA4nfnpLTF31YuE.............JFtKjrTQC1K","token_type":"bearer"}
My code:
final RequestQueue queue = Volley.newRequestQueue(this);
final String url = "https://api.twitter.com/oauth2/token";
final String requestBody = "grant_type=client_credentials";
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, url, requestBody, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.i("onResponse", response.toString());
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("onErrorResponse", error.toString());
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = new HashMap<>();
// Basic Authentication
//String auth = "Basic " + Base64.encodeToString(CONSUMER_KEY_AND_SECRET.getBytes(), Base64.NO_WRAP);
String auth = "Basic cjMzZXVWeG5ZSDN3NjJ1RUdhV1NtcDAzYzpDa0h5Q3N1ZXF5ZXVobTExWURnTmpKMUZWRFN6OEk5TDFXWXJVUTFQWTNPZTcxcWlGdQ==";
headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
headers.put("Authorization", auth);
return headers;
}
};
queue.add(jsonObjectRequest);
private void fetchAccessTokens() {
final String requestBody = "grant_type=client_credentials";
JsonObjectRequest req1 = new JsonObjectRequest(Request.Method.POST,
TwitterTokenURL,
null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.i("Response: ", response.toString());
fetchTweets(response.toString());
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}){
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = new HashMap<>();
// URL encode the consumer key and secret
String urlApiKey = null;
String urlApiSecret = null;
try {
urlApiKey = URLEncoder.encode(CONSUMER_KEY, "UTF-8");
urlApiSecret = URLEncoder.encode(CONSUMER_SECRET, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// Concatenate the encoded consumer key, a colon character, and the
// encoded consumer secret
String credentials = urlApiKey + ":" + urlApiSecret;
String auth = "Basic "
+ Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
headers.put("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
headers.put("Authorization", auth);
return headers;
}
#Override
public byte[] getBody() {
return requestBody.getBytes();
}
};
AppController.getInstance().addToRequestQueue(req1, tag_json_arry);
}
I'm trying to send a JsonObjectRequest to my server with some params, but seems like params doesn't arrive at the server. Before to post on SO I try all kind of suggestion found in google but no one works fine..
This is the code of my JsonObjectRequest:
RequestQueue queue = MySingleVolley.getInstance(ctx).
getRequestQueue();
JsonObjectRequest jsObjRequest = new JsonObjectRequest(method,url,null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d("REQUEST_JSON_TO_SERVER", "Success: " + response.toString());
}
},new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("REQUEST_JSON_TO_SERVER", "Error: " + error);
}
}){
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json");
return headers;
}
#Override
protected Map<String, String> getParams() {
return params;
}
};
MySingleVolley.getInstance(ctx).addToRequestQueue(jsObjRequest);
And these are my param and others:
String url = "url";
//create the hashMap of parameters
database_zappapp db = new database_zappapp(getApplicationContext());
db.open();
HashMap<String, String> params = new HashMap<>();
params.put("action","myAction");
params.put("nomeutente", db.getUsernameLogged());
params.put("token", token);
db.close();
//Send the request to the server
Global.RequestJsonToServer(getApplicationContext(), url, Request.Method.POST, params);
Thanks in advance for the help!
Edit 2
I've changed my params in this creating a string jsonBody:
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("action","gcmUserRegister");
jsonObject.put("nomeutente",db.getUsernameLogged());
jsonObject.put("token",token);
}catch(JSONException e){
e.printStackTrace();
}
String requestBody = jsonObject.toString();
db.close();
and my request like this with getBody():
JsonObjectRequest jsObjRequest = new JsonObjectRequest(method,url,null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d("REQUEST_JSON_TO_SERVER", "Success: " + response.toString());
}
},new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("REQUEST_JSON_TO_SERVER", "Error: " + error);
}
}){
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
return headers;
}
#Override
public byte[] getBody() {
try {
return requestBody == null ? null : requestBody.getBytes("utf-8");
} catch (UnsupportedEncodingException uee) {
VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s",
requestBody, "utf-8");
return null;
}
}
};
But already didn't work! =(
Postman screen:
No user found means that it enter in the if statement and so it works.. with android i receive "result": "null"
The postman screen with app/json:
I've found the solution!
The problem was in the server not in the client, I was getting the data using POST but from the client I was sending a json object so my new php is:
$data = json_decode(file_get_contents('php://input'), true);
//echo "Action: ".$action;
//Registrazione del token
if($data['action'] == "gcmUserRegister"){
......
Thanks al lot to BKS!!!
Change this part of your code:
`JsonObjectRequest jsObjRequest = new JsonObjectRequest(method,url,null ...`
To this:
`JsonObjectRequest jsObjRequest = new JsonObjectRequest(method,url,yourparams..`
Reason: if you are using the default Volley constructors thats the way to send params to Server.
I am attempting a Volley POST request that passes in the parameter friends_phone_number_csv that should then return a JSON object. However in using the request below it simply notes:
E/Volley﹕ [4230] BasicNetwork.performRequest: Unexpected response code 500 for http://(ip-address):3000/getActivatedFriends.json
In testing this request in chromes POSTMAN I know the webservice is correct and should return a JSON object.
How can I make this work?
The POST request in app:
JsonObjectRequest getUserActiveFriends = new JsonObjectRequest(Request.Method.POST, "http://" + Global.getFeastOnline() + "/getActivatedFriends.json",
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// Parse the JSON:
try {
resultObject = response.getJSONObject("friends_match");
Toast.makeText(getApplicationContext(), resultObject.toString(), Toast.LENGTH_LONG).show();
// PARSE THE REST
//Log.v("USER ID", "The user id is " + userId);
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// error
Log.d("Error.Response", error.toString());
}
}
) {
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
params.put("friends_phone_number_csv", contactsNumbers);
return params;
}
};
requestQueue.add(getUserActiveFriends);
You should add this code, when you post request and return json data, you should add content type "application/json; charset=utf-8" to http header.
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json; charset=utf-8");
return headers;
}
I am trying to update data on server by using PUT method but I am getting this error , I haven't used volley before ,Is there anything I am missing ? please suggest .
My code :
private void sendRequest() {
RequestQueue queue = Volley.newRequestQueue(getActivity());
PersonalInfoModel.Data.PersonalInformation.Address address;
address = new PersonalInfoModel().new Data().new PersonalInformation().new Address();
address.setBuilding("test");
address.setCountry("test");
address.setCounty("test");
address.setPostcodeInCode("");
address.setPostcodeOutCode("");
address.setTown("");
PersonalInfoModel.Data.PersonalInformation data;
data = new PersonalInfoModel().new Data().new PersonalInformation();
data.setDob("tsst");
data.setEmail("testemai");
data.setForename("test");
data.setSurname("data");
data.setAddress(address);
Gson gson = new Gson();
JSONString = gson.toJson(data);
try {
obj = new JSONObject(JSONString);
} catch (JSONException e) {
e.printStackTrace();
}
LogUtils.LOGD(TAG, "JSONString is :: " + JSONString.toString());
JsonObjectRequest putRequest = new JsonObjectRequest(Request.Method.PUT, urlUserDetail, obj,
new Response.Listener<JSONObject>()
{
#Override
public void onResponse(JSONObject response) {
// response
LogUtils.LOGD("Response", response.toString());
}
},
new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error) {
// error
LogUtils.LOGD("Error.Response", error.toString());
}
}
) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("tess", "2222");
params.put("Authorization", "def1bc98d032");
params.put("Content-Type", "application/json; charset=utf-8");
return params;
}
#Override
public byte[] getBody() {
try {
LogUtils.LOGD("json", obj.toString());
return obj.toString().getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
};
queue.add(putRequest);
}
Error :
BasicNetwork.performRequest: Unexpected response code 400 for url
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("tess", "2222");
params.put("Authorization", "def1bc98d032");
// add this parameter
params.put("Content-Type", "application/json; charset=utf-8");
return params;
}
Check with PostMan or some client and check if you are getting a right response back and eliminate that possibility - the request works without using android volley
Response code 400 means Bad request. It means that the request you're making is incorrect. Possibly the content type has an error, try adding
params.put("Content-Type", "application/json; charset=utf-8"); to getHeaders()
try removing the getbody method.. because you are sending the request parameters as a json object and content type header is also application/json.so getbody won't be necessary
JsonObjectRequest adds Content-Type: application/json; charset=utf-8 by default. Your params.put("Content-Type", "application/json; charset=utf-8"); adds another Content-Type and some applications don't work with multiple Content-Type definitions. You should try to remove params.put("Content-Type", "application/json; charset=utf-8");.
Make sure that the request URL for a PUT request has the id of the resource as the last path segment. Otherwise you will get a 404.
Wrong form of URL:
/users
Correct form of URL:
/users/bob
I'm looking through examples and code but I don't see anything implemented. Is this possible at this stage?
For those who don't want to use Spring for Android just for that, here's how to do it.
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> params = new HashMap<String, String>();
String creds = String.format("%s:%s","USERNAME","PASSWORD");
String auth = "Basic " + Base64.encodeToString(creds.getBytes(), Base64.DEFAULT);
params.put("Authorization", auth);
return params;
}
Note that you may have to use Base64.NO_WRAP instead of Base64.DEFAULT for this to work. As pointed in the comments.
API 8+
Yes it's possible. You need to override Request.getHeaders(). I'm lazy and I used HttpHeaders and HttpAuthentication from Spring for Android but you can just build the auth header and return it from the method. From getHeaders() you can return the auth header for basic auth. This is a sample request with basic auth.
public class GetUser extends Request<User> {
private static final String TAG = GetUser.class.getName();
private Response.Listener<User> mListener;
private ObjectMapper mMapper = new ObjectMapper();
public GetUser(Response.ErrorListener errorListener, Response.Listener<User> listener){
super(Method.GET, PoisUtils.BASE_URL + "/users", errorListener);
mListener = listener;
}
#Override
protected Response<User> parseNetworkResponse(NetworkResponse response) {
String jsonString = new String(response.data);
try {
User result = mMapper.readValue(jsonString, User.class);
return Response.success(result, getCacheEntry());
} catch (IOException e) {
Log.d(TAG, e.getMessage());
}
return null;
}
#Override
protected void deliverResponse(User response) {
mListener.onResponse(response);
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
return AuthUtils.buildAuthHeaders().toSingleValueMap();
}
}
And here is how I build the auth headers
public static HttpHeaders buildAuthHeaders(){
if(UserUtils.isUserLogged()){
HttpHeaders requestHeaders = new HttpHeaders();
User user = PoisApplication.get().getUser();
HttpAuthentication auth = new HttpBasicAuthentication(
user.getUsername(), user.getPassword());
requestHeaders.setAuthorization(auth);
return requestHeaders;
}
return null;
}
For a proxy authorization (like squid) use this header :
String credentials = proxyUsername + ":" + proxyPassword;
String auth = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
headers.put("Proxy-Authorization", auth);