I have a method named getResponse() in my program:
public ClosableHTTPResponse getResponse()
{
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(120 * 1000).build();
CloseableHttpClient httpClient = null;
CloseableHttpResponse response = null;
try {
httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
HttpGet httpPostRequest = new HttpGet(getURL);
httpPostRequest.addHeader("Authorization", "Token " + APIKey);
httpPostRequest.setHeader("Content-type", "application/json");
response = httpClient.execute(httpPostRequest);
String statusLine = response.getStatusLine().toString();
System.out.println("Status Line Response: " + statusLine);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (response != null) response.close();
if (httpClient != null) httpClient.close();
}
return response;
}
}
When I call this method from external method in the following code:
public void analzyeReponseA()
{
CloseableHttpResponse response = null;
try {
response = getResponse("p1", "p2");
String OKResponse = "HTTP/1.1 200 OK";
String statusLine = response.getStatusLine().toString();
if (statusLine.contains(OKResponse)) {
HttpEntity entity = response.getEntity();
// java.net.SocketException: Socket is closed exception thrown on next line..
String responseString = EntityUtils.toString(entity, "UTF-8");
System.out.println("Response String:\n" + responseString);
}
}
I'm getting a java.net.SocketException: Socket is closed exception
on this line:
String responseString = EntityUtils.toString(entity, "UTF-8");
Based on this and this thread, presumably this is happening bec I call if (response != null) response.close(); in getResponse() method (correct?)
If so, my question now is how do I return a CloseableHttpResponse without the program throwing above exception? Is the only option to call String responseString = EntityUtils.toString(entity, "UTF-8"); in getReponse() method and return a responseString instead of CloseableHttpResponse? What if I still want to access the response object in caller code (like to check status line or something else)?
If I understood the question correctly, I'd first look to see if the code really needed to return an HttpResponse. If the method(s) that call getResponse() all only need, e.g, the contents, then return the contents rather than the response.
Otherwise, you should be able to do, using the try-with-resources approach:
public void callingMethod() {
try (CloseableHttpResponse resp = getResponse();) {
{
// example
HttpEntity entity = resp.getEntity();
}
}
And remove the close from the getResponse() method.
Also, you do not want to be opening/closing the HttpClient on each invocation. That class is designed to be used multiple times. There is more information at You're Using HttpClient wrong and it is destabilizing your software. Thus, you may wish to refactor the code to move the HttpClient elsewhere.
Related
I have the following java code with try with resources:
public static CloseableHttpResponse getHttpResponse()
{
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
try (CloseableHttpResponse response = client.execute(request)) {
return response;
}
}
}
in another method will use the response returned by getHttpResponse:
public void test() {
CloseableHttpResponse response = getHttpResponse();
if (response) {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
// do something
}
}
}
Looks like after CloseableHttpResponse response = getHttpResponse();, the client and response already closed, and I can not put this two methods into one, are there any ways that still use the try with resources in another method?
The best approach is the Execute Around idiom. Instead of getHttpResponse returning a CloseableHttpResponse pass in a lambda (typically) to be executed. The resource can then be closed in a try-with-resource statement cleanly.
/*** NICE ***/
// Function instead of Consumer would allow the method to return a value.
private void httpResponse(
Consumer<CloseableHttpResponse> op
) /* throws IOException */ {
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
try (CloseableHttpResponse response = client.execute(request)) {
if (response != null) { // Really?
op.accept(response);
}
}
}
}
Used as:
httpResponse(response -> {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
// do something
}
});
The hacky alternative is to include a try statement within getHttpResponse that only closed in error conditions.
/*** HACKY ***/
private CloseableHttpResponse httpResponse() /* throws IOException */ {
boolean success = false;
CloseableHttpClient client = HttpClientBuilder.create().build();
try {
CloseableHttpResponse response = client.execute(request);
try {
success = true;
return response;
} finally {
if (!success) {
response.close();
}
}
} finally {
if (!success) {
client.close();
}
}
}
client will be closed as soon as the program leaves the scope of the try-with-resources. Can you try building the try with resources around the getHttpResponse method? For example:
public static CloseableHttpResponse getHttpResponse() {
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
CloseableHttpResponse response = client.execute(request)
return response;
}
}
And then you can rewrite your test method() like this:
public void test() {
try(CloseableHttpResponse response = getHttpResponse()) {
if (response) {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
// do something
}
}
}
}
I have a httpClient function which returns an HttpResponse object to the calling function.
public HttpResponse postRequest(String uri, String body) throws IOException {
HttpResponse response;
String url = baseUrl + uri;
try (CloseableHttpClient httpClient = HttpClientBuilder.create()
.build()) {
HttpPost post = new HttpPost(url);
post.setEntity(new StringEntity(body));
post.setHeader(AUTHORIZATION_HEADER, authorization);
post.setHeader(CONTENTTYPE_HEADER, APPLICATION_JSON);
post.setHeader(ACCEPT_HEADER, APPLICATION_JSON);
response = httpClient.execute(post);
} catch (IOException e) {
System.out.println("Caught an exception" + e.getMessage().toString());
logger.error("Caught an exception" + e.getMessage().toString());
throw e;
}
return response;
}
In my calling function I call, HttpResponse response = httpRequest.postRequest(url,body); (where httpRequest is an object for the class which contains the function
When I try to parse the contents of the received the response through
String responseString = IOUtils.toString(response.getEntity()
.getContent(), "UTF-8");
I get an error Socket is closed.
How do I use the contents of HttpResponse once the connection is closed?
Your try-with-resources statement is closing the entire client. You don't want that. Remove it. You want the close to happen when the caller closes the response you're returning.
I've been trying to get a simple android client server app working, and I've had nothing but trouble. I'm hoping someone can look at this code and see what I'm doing wrong, maybe I'm doing things in the wrong order, or forgetting something? Just adding the relevant parts
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.addRequestProperty("Content-Type", "application/json");
// set some made up parameters
String str = "{'login':'superman#super.com','password':'password'}";
byte[] outputInBytes = str.getBytes("UTF-8");
OutputStream os = conn.getOutputStream();
os.write( outputInBytes );
os.close();
// connection.setDoOutput(true); //should trigger POST - move above -> crash
conn.setRequestMethod("POST"); // explicitly set POST -move above so we can set params -> crash
conn.setDoInput(true);
The error I get is
'exception: java.net.ProtocolException: method does not support a
request body: GET'
If I just do a POST request without parameters it's fine, so I guess I should move the connection.setDoOutput(true); or conn.setRequestMethod("POST"); higher up, that should work right? When I do that I get the error:
exception: java.net.ProtocolException: Connection already established.
So, if I try to set to POST before adding parameters it doesn't work, if I try to do it after it doesn't work... what am I missing? Is there another way I should be doing this? Am I adding parameters incorrectly? I've been searching for a simple android networking example, and I can't find any, is there any example the official Android site? All I want to do is a very basic network operation, this is so frustrating!
EDIT: I need to use HttpsURLConnection for reasons not included in the above code- I need to authenticate, trust hosts, etc- so I'm really looking for a potential fix for the above code if possible.
Here is an example of how to post with a JSON Object:
JSONObject payload=new JSONObject();
try {
payload.put("password", params[1]);
payload.put("userName", params[0]);
} catch (JSONException e) {
e.printStackTrace();
}
String responseString="";
try
{
HttpPost httpPost = new HttpPost("www.theUrlYouQWant.com");
httpPost.setEntity(new StringEntity(payload.toString()));
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-type", "application/json");
HttpResponse response = new DefaultHttpClient().execute(httpPost);
responseString = EntityUtils.toString(response.getEntity());
}
catch (ClientProtocolException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
And example of how to get
String responseString = "";
//check if the username exists
StringBuilder builder = new StringBuilder();
HttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet("www.theUrlYouQWant.com");
ArrayList<String> existingUserName = new ArrayList<String>();
try
{
HttpResponse response = client.execute(httpGet);
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == 200) {
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(content));
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
}
else
{
Log.e(ParseException.class.toString(), "Failed to download file");
}
}
catch (ClientProtocolException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
I followed this tutorial on making http calls:
http://www.androidhive.info/2012/01/android-json-parsing-tutorial/
Works fine with no problems.
Below is a class that I have modified from the sample:
public class ServiceHandler {
static String response = null;
public final static int GET = 1;
public final static int POST = 2;
String TAG = ((Object) this).getClass().getSimpleName();
public ServiceHandler() {
}
/**
* Making service call
*
* #url - url to make request
* #method - http request method
*/
public String makeServiceCall(String url, int method) {
return this.makeServiceCall(url, method, null);
}
/**
* Making service call
*
* #url - url to make request
* #method - http request method
* #params - http request params
*/
public String makeServiceCall(String url, int method,
List<NameValuePair> params) {
try {
// http client
HttpParams httpParameters = new BasicHttpParams();
// Set the timeout in milliseconds until a connection is established.
// The default value is zero, that means the timeout is not used.
int timeoutConnection = 2000;
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
// Set the default socket timeout (SO_TIMEOUT)
// in milliseconds which is the timeout for waiting for data.
int timeoutSocket = 2000;
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
HttpEntity httpEntity = null;
HttpResponse httpResponse = null;
// Checking http request method type
if (method == POST) {
HttpPost httpPost = new HttpPost(url);
// adding post params
if (params != null) {
httpPost.setEntity(new UrlEncodedFormEntity(params));
}
httpResponse = httpClient.execute(httpPost);
} else if (method == GET) {
// appending params to url
if (params != null) {
String paramString = URLEncodedUtils
.format(params, "utf-8");
url += "?" + paramString;
}
Log.e("Request: ", "> " + url);
HttpGet httpGet = new HttpGet(url);
httpResponse = httpClient.execute(httpGet);
}
if (httpResponse != null) {
httpEntity = httpResponse.getEntity();
} else {
Log.e(TAG, "httpResponse is null");
}
response = EntityUtils.toString(httpEntity);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
}
And this is how I use the class:
nameValuePairs = new ArrayList<NameValuePair>();
String param_value = "value";
String param_name = "name";
nameValuePairs.add(new BasicNameValuePair(param_name, param_value));
// Creating service handler class instance
sh = new ServiceHandler();
String json = sh.makeServiceCall(Utils.getUrl, ServiceHandler.GET, nameValuePairs);
I am creating a httpClient and I want to add certain header to my HttpGet request
My current code produces the following request.
GET /folder/index.html HTTP/1.0
Host: localhost:4444
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.2.1 (java 1.5)
What I want is to add another header (If-Modified-Since) in that request .
How can I do it?
Thank you :)
public String httpGet(String s) {
String url = s;
StringBuilder body = new StringBuilder();
httpclient = new DefaultHttpClient(); // create new httpClient
HttpGet httpGet = new HttpGet(url); // create new httpGet object
try {
response = httpclient.execute(httpGet); // execute httpGet
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
// System.out.println(statusLine);
body.append(statusLine + "\n");
HttpEntity e = response.getEntity();
String entity = EntityUtils.toString(e);
body.append(entity);
} else {
body.append(statusLine + "\n");
// System.out.println(statusLine);
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
httpGet.releaseConnection(); // stop connection
}
return body.toString(); // return the String
}
Use the setHeader() method on the HttpGet object like follows.
httpGet.setHeader("If-Modified-Since","11/26/2012");
I used this JavaDoc as a reference.
Use the setHeader() method on the HttpGet object like follows for the first one
httpGet.setHeader("If-Modified-Since","11/26/2012");
and then use addHeader() method on the HttpGet object like as follows for the second header.
httpGet.addHeader("If-Expires-On","11/26/2014");
In my app, I need to send all sorts of POST requests to a server. some of those requests have responses and others don't.
this is the code I'm using to send the requests:
private static final String TAG = "Server";
private static final String PATH = "http://10.0.0.2:8001/data_connection";
private static HttpResponse response = null;
private static StringEntity se = null;
private static HttpClient client;
private static HttpPost post = null;
public static String actionKey = null;
public static JSONObject sendRequest(JSONObject req) {
try {
client = new DefaultHttpClient();
actionKey = req.getString("actionKey");
se = new StringEntity(req.toString());
se.setContentEncoding(new BasicHeader(HTTP.CONTENT_ENCODING, "application/json"));
se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
post = new HttpPost(PATH);
post.setEntity(se);
Log.d(TAG, "http request is being sent");
response = client.execute(post);
Log.d(TAG, "http request was sent");
if (response != null) {
InputStream in = response.getEntity().getContent();
String a = convertFromInputStream(in);
in.close();
return new JSONObject(a);
}
} catch (UnsupportedEncodingException e) {
Log.d(TAG, "encoding request to String entity faild!");
e.printStackTrace();
} catch (ClientProtocolException e) {
Log.d(TAG, "executing the http POST didn't work");
e.printStackTrace();
} catch (IOException e) {
Log.d(TAG, "executing the http POST didn't work");
e.printStackTrace();
} catch (JSONException e) {
Log.d(TAG, "no ActionKey");
e.printStackTrace();
}
return null;
}
private static String convertFromInputStream(InputStream in)
throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line);
}
return (sb.toString());
}
This is the code for the AsyncTask class that sends the request:
class ServerRequest extends AsyncTask<JSONObject, Void, JSONObject> {
#Override
protected JSONObject doInBackground(JSONObject... params) {
JSONObject req = params[0];
JSONObject response = Server.sendRequest(req);
return response;
}
#Override
protected void onPostExecute(JSONObject result) {
// HANDLE RESULT
super.onPostExecute(result);
}
}
my problem starts when the server doesn't return a response. the AsyncTask thread stays open even after the work is done because the HTTPClient never closes the connection.
Is there a way to not wait for a response? this is something that will definitely add a lot of overhead to the server since all the Android apps trying to connect to it will keep the connection alive, and will probably cause many problems on the app itself.
Basically, what I'm looking for is a method that will allow me to send to POST message and kill the connection right after the sending of the request since there is no response coming my way.
Just, Set ConnectionTimeOut with HttpClient Object, (Code is for your understanding in your case it may be different)
int TIMEOUT_MILLISEC = 30000;
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, TIMEOUT_MILLISEC);
HttpConnectionParams.setSoTimeout(httpParams, TIMEOUT_MILLISEC);
HttpClient httpclient = new DefaultHttpClient(httpParams);
HttpPost httppost = new HttpPost(url);
httppost.addHeader("Content-Type", "application/json");
Now, It will terminate the Connection after TimeoOut you defined. But be sure this will throw TimeOutException so You have to handle this exception in your HttpRequest.. (Use Try -catch)
EDIT: Or you can use HttpRequestExecutor class.
From class HttpRequestExecutor of package org.apache.http.protocol
protected boolean canResponseHaveBody (HttpRequest request, HttpResponse response)
Decide whether a response comes with an entity. The implementation in this class is based on RFC 2616. Unknown methods and response codes are supposed to indicate responses with an entity.
Derived executors can override this method to handle methods and response codes not specified in RFC 2616.