Just a little starter information. I am writing an Andorid app that talks to a server written in C#.Net using the MVC platform. Every request is a post and a ActionFilter attribute ensures that. However because of the issue .Net parses the HttpMethod as "ST".
The following is the code I use globally to make web requests from my application:
private String MakeRequest(String action, String params){
try {
HttpPost request = new HttpPost(mProtocol + mSubDomain + mHost + action);
String args;
if (params != null) {
args = params;
} else {
args = "[]";
}
StringEntity requestEntity;
requestEntity = new StringEntity(args);
requestEntity.setContentType("application/json;charset=UTF-8");
requestEntity.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE,"application/json;charset=UTF-8"));
request.setEntity(requestEntity);
HttpResponse response = mHttpClient.execute(request);
HttpEntity responseEntity = response.getEntity();
String jString = EntityUtils.toString(responseEntity);
return jString;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
I only have this problem with one particular method all other methods work just fine.
The following link is to a pcap file that contains the traffic so it is plainly visible. (I have filtered it down to only the applicable lines)
http://dl.dropbox.com/u/315661/defect.pcap
Have you tried disabling the use of 100-Continue in your POST? You typically don't need it as it only adds more overhead to your communication with the server - and it can cause issues if the service (or any piece of kit on the way between your device and the service, such as proxies etc.) you are posting to is not completely conformant.
HttpProtocolParams.setUseExpectContinue(params, false)
Related
I'm trying to use Twitter's friends list api and was successful to do so without any parameters.
However whenever I add a parameter, I would get the error "Could not authenticate you." and I have no choice but to add a cursor parameter when the friend list is too long.
The fact that I get a list of users of friends when I call the api without any parameters makes me think that authenticating the request works properly.
I have tried to change the request url to https://api.twitter.com/1.1/friends/list.json?cursor=-1 which gives me the authentication error.
I tried using both https://api.twitter.com/1.1/friends/list.json and https://api.twitter.com/1.1/friends/list.json?cursor=-1 to make oauth_signature and they both failed me.
I tried using different parameters such as screen_name or user_id and they all will give me the same error.
I even tried to add cursor: -1 header like a POST request and that didn't work either.
Right now my code looks like this
public String getFriendList() {
String baseUrl = "https://api.twitter.com/1.1/friends/list.json";
// Creates a map with all necessary headers
Map<String, String> headers = createMap();
headers.put("oauth_token", <OAuth token of user>);
String signature = createSignature("GET", baseUrl, headers, <OAuth secret of user>);
// Add oauth_signature to header
headers.put("oauth_signature", signature);
String body = sendGetRequest(baseUrl, headers);
return body;
}
public String sendGetRequest(String baseUrl, Map<String, String> parameters) throws AuthException, IOException {
try (CloseableHttpClient client = CloseableHttpClientFactory.getHttpClient()) {
HttpGet httpGet = new HttpGet(baseUrl);
if (parameters != null) {
httpGet.setHeader("Authorization", createHeader(parameters));
}
CloseableHttpResponse response = client.execute(httpGet);
if (response.getStatusLine().getStatusCode() != 200) {
LOGGER.info("GET Request Failed : " + EntityUtils.toString(response.getEntity()));
throw new Exception();
}
String responseBody = EntityUtils.toString(response.getEntity());
return responseBody;
}
}
which is the working code.
Could anyone tell me where to add parameters and what I have missed to authenticate the request?
EDIT : Added code of sendGetRequest. Making the signature and adding the header was made by following the documentations from twitter
I'm currently migrating an application from jersey 1 to 2. In the old app, we used a ClientFilter for all jersey clients that automatically refreshed expired OAuth tokens like this:
#Override
public ClientResponse handle(ClientRequest cr) {
ClientResponse resp = getNext().handle(cr);
if (resp.getStatus() == Status.UNAUTHORIZED.getStatusCode()) {
// Try to refresh the token
boolean refreshed = refreshToken(oAuthInfo);
if (refreshed) {
resp = getNext().handle(cr);
}
}
return resp;
}
It might not haven been the most elegant way, but the benefit was that rest client users did not have to care about expired tokens themselves.
With the ContainerResponseFilter for jersey 2, this does not seem to be that simple anymore. The only option I currently see is to use the ClientRequestContext and try to re-create the original request using getClient, getHeaders etc... and then update the result in ContainerResponseContext. This however seems a bit clunky so I was wondering if there is any more convenient way to refresh an OAuth token without having to deal with this wherever a jersey client is used?
It looks like there is not more convenient way than intercepting the response with a client filter, refreshing the token if needed and trying to repeat the exact same request with the new token. In fact, this approach is also used by jersey own filter classes.
Sample code for repeating the original rest call from within a filter class can be found in jerseys HttpAuthenticationFilter:
static boolean repeatRequest(ClientRequestContext request, ClientResponseContext response, String newAuthorizationHeader) {
Client client = request.getClient();
String method = request.getMethod();
MediaType mediaType = request.getMediaType();
URI lUri = request.getUri();
WebTarget resourceTarget = client.target(lUri);
Invocation.Builder builder = resourceTarget.request(mediaType);
MultivaluedMap<String, Object> newHeaders = new MultivaluedHashMap<String, Object>();
for (Map.Entry<String, List<Object>> entry : request.getHeaders().entrySet()) {
if (HttpHeaders.AUTHORIZATION.equals(entry.getKey())) {
continue;
}
newHeaders.put(entry.getKey(), entry.getValue());
}
newHeaders.add(HttpHeaders.AUTHORIZATION, newAuthorizationHeader);
builder.headers(newHeaders);
builder.property(REQUEST_PROPERTY_FILTER_REUSED, "true");
Invocation invocation;
if (request.getEntity() == null) {
invocation = builder.build(method);
} else {
invocation = builder.build(method,
Entity.entity(request.getEntity(), request.getMediaType()));
}
Response nextResponse = invocation.invoke();
if (nextResponse.hasEntity()) {
response.setEntityStream(nextResponse.readEntity(InputStream.class));
}
MultivaluedMap<String, String> headers = response.getHeaders();
headers.clear();
headers.putAll(nextResponse.getStringHeaders());
response.setStatus(nextResponse.getStatus());
return response.getStatus() != Response.Status.UNAUTHORIZED.getStatusCode();
}
This code is used for example in DigestAuthenticator or BasicAuthenticator to repeat a request with provided credentials in case an Unauthorised response is received from server.
I need a little help with this, I've used HTTP requests before but through JavaScript when I was using AJAX, it looks similar but I'm not entirely sure how to do all of it properly. I've seen some people's codes and stuff, but I'm not sure about two things. First, I want to send an int through the POST in order to identify which query should be called and what data should be sent back through the response. Second, I'm not sure about the URL, do I need a domain? I just need to connect to a server on my machine which I'm using with XAMPP. I'm not entirely sure how to do this? Do I just place a URL with my machine's IP with a port or something?
So here's what I've attempted:
public class Request {
private static Request instance;
private static String URL;
private String requestResult;
private String error;
private Request(){
this.URL = "http://IPAddress or Server Address/Android Webservice/webservice.php"; /* not sure what I should use here, I'm using an apache server */
this.error = new String();
this.requestResult = new String();
}
public static Request getRequest(){
if(instance == null){
instance = new Request();
}
return instance;
}
public void sendHttpPostRequest(String option){
HttpClient client = new DefaultHttpClient();
HttpPost postRequest = new HttpPost(URL);
HttpResponse serverResponse;
String jsonToSend = "message={identifer:" + option + "}";
NameValuePair parameter = new BasicNameValuePair("data", jsonToSend);
try {
StringEntity entity = new StringEntity(jsonToSend);
postRequest.addHeader("content-type", "application/x-www-form-urlencoded");
postRequest.setEntity(entity);
serverResponse = client.execute(postRequest);
} catch (Exception e){
}
}
public String getURL() {
return this.URL;
}
public String getResult(){
return this.requestResult;
}
}
I've got it in a class, because I want to be able to call it anywhere, plus I need to call it in multiple views in my android application. I would say the most important part in here is the `sendHttpPostRequest. However I'm not sure how to go about using that response to do anything. Normally with AJAX I'd just get the response text and go from there, but that doesn't work here. I've seen various examples but I'm having a hard time getting them, and some of them do a lot of stuff that I'm not sure I need.
For instance this is my PHP file:
<?php
$obj = json_decode($_POST['message']);
$obj = json_decode($dataReceived,true);
$data = array("data","some other data","the last piece of data");
json_encode('data'=>$data);
echo $data;
?>
For now it looks like this because this is a simple test, but what the end goal should be is to return an an associative array which would be the result of a query from my database. I know how to do that easily, but I'm not sure how to send the request to get this file to return that stuff. I don't know how to parse a JSON within Java, especially an associative array and I'm also not sure how my server should be configured to allow connections from android devices.
So what exactly needs to go in the URL to connect to my PC? How do I parse JSON response and then convert it into data that I can place in my android application? How do I go about moving anywhere with this device, and retrieving this data from a location far from my server?
I'm hoping that this doesn't require payment of any sort, I mean the server is on my computer after all.
I'm in the midst of testing my application which is using an HTTP-server. Instead of mocking I decided to go with a HTTP server fixture. Meaning that I do not have to mock any productional code. To accomplish this goal I currently chose for a free to use 3rd party library fixd.
I was able to successfully create several unit tests - which are working by means of a GET request. Most are quite simple, i.e.:
#Test
public void verifyConnectionTest()
{
try
{
final String body = FileUtils.readFileToString(RESOURCE);
final String path = "/";
this.server.handle(Method.GET, path).with(
new HttpRequestHandler() {
#Override
public void handle(final HttpRequest request,
final HttpResponse response)
{
response.setStatusCode(200);
response.setContentType("text/xml");
response.setBody(body);
}
});
// Setting up my HTTP client
// Execute some tasks
// asserting of everything was valid
}
catch (final IOException e)
{
fail(e.getMessage());
}
}
But I now have to send a POST request with multipart/form-data. Which does not make much of a difference other than changing the method and content-type:
#Test
public void executeStepTest()
{
try
{
final String body = FileUtils.readFileToString(SERVICE_RESPONSE);
final String path = "/";
this.server.handle(Method.POST, path, "multipart/form-data").with(
new HttpRequestHandler() {
#Override
public void handle(final HttpRequest request,
final HttpResponse response)
{
response.setStatusCode(200);
response.setContentType("text/xml");
response.setBody(body);
}
});
// Setting up my HTTP client
// Execute some tasks
// asserting of everything was valid
}
catch (final IOException e)
{
fail(e.getMessage());
}
}
However I get the following error: [ERROR] could not find a handler for POST - / - multipart/form-data; boundary=bqCBI7t-VW1xaJW7BADmTiGMg9w_YM2sHH8ukJYx and my guess is that fixd doesn't recognize the boundary-party. Since the documentation does not show an example I'm quite stuck on this part.
I tried using some wildcards such as '*', no succes. Thus; I need a way to either tell fixd to accept that boundary or use some wildcards I didn't yet discover. Any help would be great, thanks!
I've been making some debug and it seems to be that the problem is in the fixd core.
Basically, fixd indexes every RequestHandlerImpl by a HandlerKey (which includes ContentType as part of the key) in the map handlerMap. See method org.bigtesting.fixd.core.FixtureContainer#resolve.
...
HandlerKey key = new HandlerKey(method, route, contentType);
RequestHandlerImpl handler = handlerMap.get(key);
if (handler == null) {
// Error
}
...
Problem: When the request is multipart/form-data, boundary data (which it's generated dinamically every request) is part of the content type. So, any handler is found in handlerMap because the key changes with every running.
I've made a little test only to check that this is the cause of the problem, passing the contentType to fixd server.handle after the creation of the multipart request, and it works fine.
See the test below:
#Test
public void verifyConnectionTest_multipart() {
try {
// 1. Create multipart request (example with http-commons 3.1)
PostMethod filePost = new PostMethod(url);
Part[] parts = { new StringPart("param", "value") };
MultipartRequestEntity request = new MultipartRequestEntity(parts, filePost.getParams());
filePost.setRequestEntity(request);
// 2. fixd server handle (passing the request content type)
this.server.handle(Method.POST, "/", request.getContentType()).with(
new HttpRequestHandler() {
#Override
public void handle(final HttpRequest request,
final HttpResponse response) {
response.setStatusCode(200);
response.setContentType("text/xml");
}
});
// 3. Execute multipart request
HttpClient client = new HttpClient();
int status = client.executeMethod(filePost);
// 4. Assertions
Assert.assertEquals(200, status);
} catch (Exception e) {
Assert.fail(e.getMessage());
}
}
Hope it helps you to clarify the problem. Cheers
This was a bug in fixd, and has been fixed in version 1.0.3. Your original code should work using this new version of fixd.
I've seen multiple posts about this topic, but none of them seem to be the solution to my problem.
The problem is that the JSON response from the server is getting cut off and therefore I'm getting a JSONException when trying to get the response into a JSONArray.
json = new JSONArray(EntityUtils.toString(response.getEntity()));
Here is the whole code:
private class AsyncFetchForms extends AsyncTask<String, Void, JSONArray> {
private HttpClient mClient = new DefaultHttpClient();
private AsyncTaskCompleteListener<JSONArray> listener;
private String serverUrl;
private String credentials;
private ProgressDialog progressDialog;
private HttpGet httpGet;
private String response;
private BasicResponseHandler responseHandler;
private boolean showDialog;
private JSONArray json;
public AsyncFetchForms(String url, String message, AsyncTaskCompleteListener<JSONArray> listener, boolean showDialog)
{
serverUrl = Utils.getServerUrl(context) + url;
credentials = Utils.getUserCredentials(context);
this.listener = listener;
this.showDialog = showDialog;
httpGet = new HttpGet(serverUrl);
httpGet.setHeader("Authorization", "Basic " + credentials);
httpGet.setHeader("Accept", "application/json");
httpGet.setHeader("Accept-Encoding", "gzip");
httpGet.setHeader("Connection", "keep-alive");
responseHandler = new BasicResponseHandler();
if(showDialog)
{
progressDialog = new ProgressDialog(context);
progressDialog.setMessage(message);
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.show();
}
}
#Override
protected JSONArray doInBackground(String... params) {
try {
HttpResponse response = mClient.execute(httpGet);
if (response.getStatusLine().getStatusCode() == 200) {
json = new JSONArray(EntityUtils.toString(response.getEntity()));
return json;
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(JSONArray result) {
System.out.println(result.toString());
}
}
Can anyone see the problem?
Logcat can only show about 4000 characters. So you will have to implement a recursive function to see the entire log. Use below function to see the entire log:
public static void longInfo(String str) {
if (str.length() > 4000) {
Log.d("", str.substring(0, 4000));
longInfo(str.substring(4000));
} else
Log.d("", str);
}
If you (or your team) implement the server side yourself, first thing I'd check is if the server is returning the correct HTTP response. In particular, if you transfer the data by HTTP, you need to have correct Content-Length or otherwise your data will be cut off. Also, Content-Length must be the length of data after any Transfer Encodings are applied, in other words, after the length of the data after being gzipped. Alternatively, use chunked transfer.
Second, make sure that your server is generating valid JSON. Maybe you missed a closing parentheses or so. Maybe you need to parse JSON Object rather JSON Array.
Also, if you receive exceptions, please always post the the entire traceback.
First of all, try to log the EntityUtils.toString(response.getEntity()) response and make sure that it starts with "[" not "{" ie. it's a jsonArray not jsonObject.
Then try to open the url in your browser ,if avilable, and make sure that there are no encoding issues.
Finally, if the problem is still exists please send us the error log output.
This answer is completely out of the subject but :
What are you trying do here ? Do you know that there are libraries which are doing all this boring job for you ?
When I talk about boring job, I'm talking about managing all the background running stuff (like AsyncTask), JSON decoding and HTTP response. I know that it's sometimes a pain in the a** (I've been there) but now I've choose to not worry anymore and use a dedicated library : http://square.github.io/retrofit/
This little baby will contact the Webservice of your choice, download the JSON and put it into a custom java class with all the attributes you want to deal with.
If you plug it with something like ORMLite, it can even save your JSON response object into a SQLite DB that you can access in the same way (it "populates" a java class object by setting all the attributes for you).
Personally I can't imagine myself doing all this stuff by hand anymore, it's just trouble without the benefits =)