Does anyone have advice on making PUT requests from Android to Django REST Framework? When I post the code below to my API endpoint, specifying the record to be updated (e.g. http://mydomain/api/26), I get a response with status code 200 and the json content of the targeted record, but none of the content has been updated by the request. In contrast, when I make what appears to be an identical request via Postman or via the browsable API, it works fine, giving me the 200 response and the updated json content. Similarly, I can make POST requests to the API using nearly identical Android code with no problem. Any ideas would be wonderful. Thanks.
public static HttpResponse putJsonString(String jsonString, String targetUrl, Context context){
HttpResponse result = null;
try {
HttpParams httpParameters = new BasicHttpParams();
int timeoutConnection = 3000;
HttpConnectionParams.setConnectionTimeout(httpParameters,
timeoutConnection);
int timeoutSocket = 3000;
HttpConnectionParams
.setSoTimeout(httpParameters, timeoutSocket);
DefaultHttpClient httpclient = new DefaultHttpClient(
httpParameters);
HttpPut httpPut = new HttpPut(targetUrl);
StringEntity se = new StringEntity(jsonString, "UTF-8");
se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE,
"application/json"));
httpPut.setEntity(se);
httpPut.setHeader("Accept", "application/json");
httpPut.setHeader("Content-type", "application/json");
httpPut.setHeader("Authorization", "Token " + PropertyHolder.getUserKey());
Log.d("put", "put content: " + parseInputStream(context, httpPut.getEntity().getContent()));
result = httpclient.execute(httpPut);
} catch (UnsupportedEncodingException e) {
Util.logError(context, TAG, "error: " + e);
} catch (ClientProtocolException e) {
Util.logError(context, TAG, "error: " + e);
} catch (IOException e) {
Util.logError(context, TAG, "error: " + e);
}
return result;
}
The solution seems to be simpler than I thought: Make sure there is a trailing slash in the target URL. So http://mydomain/api/26/ instead of http://mydomain/api/26. This does not seem to matter when sending the PUT request from Postman, but from Android, omitting the trailing slash appears to cause the request to be redirected, and in the process it turns into a GET. I think the underlying issue is how the Apache HTTP client handles redirects, and it may be worthwhile to explicitly set this as well, but for now simply adding the slash does the trick.
Related
Android HTTP PUT not sending JSON request to server resulting in HTTP 405 Method not allowed.
Below is my async task background code
HttpClient httpclient = new DefaultHttpClient();
HttpPut httpPut = new HttpPut("URL");
String jsonresponse = "";
try {
StringEntity se = new StringEntity(gson.toJson(resultPojo).toString());
se.setContentType("application/json;charset=UTF-8");//text/plain;charset=UTF-8
se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE,"application/json;charset=UTF-8"));
httpPut.setEntity(se);
httpPut.setHeader("Accept", "application/json");
httpPut.setHeader("Content-type", "application/json");
HttpResponse response = httpclient.execute(httpPut);
HttpEntity httpEntity = response.getEntity();
jsonresponse = EntityUtils.toString(httpEntity);
System.out.println("res .... "+jsonresponse);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
serverside code :
#POST
#Path("{id}")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response submitUserResponse(#PathParam("userId") int userId,
#PathParam("id") int id, List<ResultPojo> responses) {
try {
//core logic goes here
return Response.status(Response.Status.CREATED).build();
} catch (Exception e) {
e.printStackTrace();
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
}
Alright just like what was discussed it is most likely a mismatch different HTTP methods, in this case A Put and a post, whenever you ever encounter that HTTP code(405) do perform a validation on the methods you used, it happens.405 errors often arise with the POST method. You may be trying to introduce some kind of input form on the Web site, but not all ISPs allow the POST method necessary to process the form.A request method is not supported for the requested resource; for example, a GET request on a form that requires data to be presented via POST, or a PUT request on a read-only resource.
I have got an prob with http post request i have set time out and on socket time out exception my data submitted on server successfully how i can restrict data to submitted on server my code is following
try{HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(
AppSettings.SERVICE_URL.POST_NEW_REGISTRATION);
HttpConnectionParams.setConnectionTimeout(
httpClient.getParams(), 5000);
HttpConnectionParams.setSoTimeout(httpClient.getParams(), 5000);
JSONObject jsonObject = new JSONObject();
jsonObject.put("agent_id", SharedPrefrence.getUserID());
httpPost.setEntity(new StringEntity(jsonObject.toString(),
"UTF-8"));
// Set up the header types needed to properly transfer JSON
httpPost.setHeader("Content-Type", "application/json");
httpPost.setHeader("Accept-Encoding", "application/json");
// Execute POST
//int getConnectionTimeout (HttpParams params);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity responseEntity = httpResponse.getEntity();
if (responseEntity != null) {
response = EntityUtils.toString(responseEntity);
} else {
response = "{'success':'FALSE'}";
}
} catch (ClientProtocolException e) {
response = "{'success':'FALSE'}";
progressDialog.cancel();
} catch (IOException e) {
response = "{'success':'FALSE','message':'Connection Time Out'}";
Log.d("Ex", e.toString());
Log.e("Ex", e.toString());
progressDialog.cancel();
} catch (JSONException e) {
response = "{'success':'FALSE','message':'JSON Parse Error'}";
progressDialog.cancel();
e.printStackTrace();
} catch (Exception e) {
response = "{'success':'FALSE'}";
progressDialog.cancel();
e.printStackTrace();
}
I think you are saying that you are getting a socket timeout exception even though the data is successfully received by the server?
If so, I think you may want to look at the value you are setting for the socket timeout - this appears to be 500ms in your code, which is quite short. It is quite possible that everything on the server side is working fine, but that the response is simply not getting to the client within 500ms.
A typical default is in the 6-10 seconds range, but it is really solution dependent so you may want to experiment. This blog post suggests some defaults for different scenarios and may be a useful reference:
http://dev.bizo.com/2013/04/sensible-defaults-for-apache-httpclient.html
probably your API call takes more than 500 ms, increase it and try again.
I seem to be having issues with the Android HTTPClient some times its super fast and other times it can take a good few seconds to return a result or says connection refused.
As a test I have tried different web hosts and direct IP also with no effect, testing is on a device connected via wifi.
The code is also running on a thread so not on the main thread.
The code i am using is as follows:
String strURL = "http://www.example.com/webservice/index.php";
List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>(2);
nameValuePairList.add(new BasicNameValuePair("command", "saveFave"));
nameValuePairList.add(new BasicNameValuePair("rid", strID));
HttpParams params = new BasicHttpParams();
params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
params.setParameter(CoreProtocolPNames.USER_AGENT, "AppName_Android");
DefaultHttpClient hc = new DefaultHttpClient(params);
HttpPost post = new HttpPost(strURL);
try {
post.setEntity(new UrlEncodedFormEntity(nameValuePairList));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
hc.setRedirectHandler(null);
HttpResponse rp = hc.execute(post);
Log.d("Http Post Response:", rp.toString());
if (rp.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
jsonData = EntityUtils.toString(rp.getEntity(), HTTP.UTF_8);
Log.v(TAG, "JSON Response " + jsonData );
} catch (Exception e) {
Log.v(TAG, "error " + e.getMessage());
}
you should be able to tweek the timeouts in debug to throw errors so you can get more data on the cause...
this.config = RequestConfig.custom()
.setConnectTimeout(6 * 1000)
.setConnectionRequestTimeout(30 * 1000)
.setSocketTimeout(30 * 1000)
.build();
That is normal behaviour on networks. I see it every day. Sometimes the first connection is fast but mostly slow. The next request goes often faster but not always. It can go slower too. For speed there is no guarantee.
How do you do write an HttpPut request with authentication on Android?
(I'm trying to work around using HttpURLConnection, which seems to serious have bugs (at least in Android 2.2) but GET works fine. I'd like to send a JSON representation of an array, and I have correct credentials already set using PasswordAuthentication.)
First you need to have an authentication token. And then just add this line.
httpGet.setHeader("Authorization", "Bearer " + yourToken);
Here's one general solution.
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, this.CONNECT_TIMEOUT);
HttpConnectionParams.setSoTimeout(httpParameters, this.CONNECT_TIMEOUT);
DefaultHttpClient client = new DefaultHttpClient(httpParameters);
// Retrieve user credentials.
SharedPreferences settings = context.getSharedPreferences("LOGIN", 0);
String loginNameString = settings.getString("login_name", null);
String passwordString = settings.getString("password", null);
UsernamePasswordCredentials credentials =
new UsernamePasswordCredentials(loginNameString, passwordString);
AuthScope authScope = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT);
client.getCredentialsProvider().setCredentials(authScope,
credentials);
HttpPut put = new HttpPut(UPLOAD_URL);
try
{
put.setEntity(new StringEntity(responseJSONArray.toString(),
SERVER_PREFERRED_ENCODING));
put.addHeader("Content-Type", "application/json");
put.addHeader("Accept", "application/json");
HttpResponse response = client.execute(put);
// 200 type response.
if (response.getStatusLine().getStatusCode() >= HttpStatus.SC_OK &&
response.getStatusLine().getStatusCode() < HttpStatus.SC_MULTIPLE_CHOICES)
{
// Handle OK response etc........
}
}
catch (Exception e)
{
}
In my Android application, i'm using ksoap2 library for consuming a soap ( & .net) webservice. It works correctly but it's very slow (for parsing, controls, loops and Base64ToBinary processes). I want to parse it more fast. Is it possible to parse it without using ksoap2? Any ideas?
Thanks for your recommendations.
What do you mean slow? It does a http request and then parses the response. You have to do this in an async task. Memory usage will depend on the response you get. Maybe you are requesting way too much. See the wiki on how to debug!
I have another problem with KSoap2. Unfortunately, ksoap2 library is not working with my webservices. So at last, I have done with default http post.
I hope this will help for someone in future.
private String makeHttpRequest(){
try{
String request = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://tempuri.org/\">"
+"<SOAP-ENV:Body>"
+ "<ns1:Connect>"
+ "<ns1:lstr_Login>xxxxx</ns1:lstr_Login>"
+"</ns1:Connect>"
+"</SOAP-ENV:Body>"
+"</SOAP-ENV:Envelope>";
String soapAction = "http://tempuri.org/Connect"; //this would be your soapAction from wsdl
StringEntity se = new StringEntity(request, HTTP.UTF_8);
DefaultHttpClient client = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(new URI("http://xxxxxxxx.com/Storefront.asmx"));
httpPost.addHeader("Content-Type", "text/xml; charset=utf-8");
httpPost.addHeader("SOAPAction", soapAction);
httpPost.setEntity(se);
HttpResponse response = client.execute(httpPost);
int responseStatusCode = response.getStatusLine().getStatusCode();
Log.d(TAG, "HTTP Status code:"+responseStatusCode);
if(responseStatusCode>=200 && responseStatusCode<300){
//we got the success response from server. Now retrieve the value and go for usage.
String responseStr = EntityUtils.toString(response.getEntity());
//use this responseStr to parse with pullparsers or any
Log.d("Response", "Response:: "+ responseStr);
return responseStr;
}
}catch(Exception e){
//Write the proper catch blocks for exceptions
Log.e("Response Exception" , e.getMessage()+"",e);
}
return null;
}