How can I retrieve the HTTP POST request body when implementing NanoHTTPDs serve method?
I've tried to use the getInputStream() method of IHTTPSession already, but I always get an SocketTimeoutException when using it inside of the serve method.
In the serve method you first have to call session.parseBody(files), where files is a Map<String, String>, and then session.getQueryParameterString() will return the POST request's body.
I found an example in the source code. Here is the relevant code:
public Response serve(IHTTPSession session) {
Map<String, String> files = new HashMap<String, String>();
Method method = session.getMethod();
if (Method.PUT.equals(method) || Method.POST.equals(method)) {
try {
session.parseBody(files);
} catch (IOException ioe) {
return new Response(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage());
} catch (ResponseException re) {
return new Response(re.getStatus(), MIME_PLAINTEXT, re.getMessage());
}
}
// get the POST body
String postBody = session.getQueryParameterString();
// or you can access the POST request's parameters
String postParameter = session.getParms().get("parameter");
return new Response(postBody); // Or postParameter.
}
On a IHTTPSession instance you can call the .parseBody(Map<String, String>) method which will then fill the map you provided with some values.
Afterwards your map may contain a value under the key postBody.
final HashMap<String, String> map = new HashMap<String, String>();
session.parseBody(map);
final String json = map.get("postData");
This value will then hold your posts body.
Code that does this, can be found here.
I think session.getQueryParameterString(); not work in this case.
If you using POST, PUT, you should want to try this code:
Integer contentLength = Integer.parseInt(session.getHeaders().get("content-length"));
byte[] buffer = new byte[contentLength];
session.getInputStream().read(buffer, 0, contentLength);
Log.d("RequestBody: " + new String(buffer));
In fact, I tried IOUtils.toString(inputstream, encoding) but it cause Timeout exception!
This is how I am getting my post response body with NanoHttp, and it works for me. Very important to note that if you are handling your own error response codes and want to send a body use the error input stream instead of the conn.getInputStream() This will avoid the file not found exception or broken pipe exception if close the connection before the server sent the body.
public HashMap<String, Object> getResponse(HttpURLConnection conn) throws IOException {
Log.i("STATUS", String.valueOf(conn.getResponseCode()));
Log.i("MSG", conn.getResponseMessage());
StringBuilder response = new StringBuilder();
String line;
BufferedReader br;
if (conn.getResponseCode() == HttpsURLConnection.HTTP_OK)
br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
else
br = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
while ((line = br.readLine()) != null)
response.append(line);
conn.disconnect();
return new Gson().fromJson(response.toString(), HashMap.class);
Related
I am trying to register a user to my Web Server. If i send valid details to the server then i get 201 code in response which stands for "created". But when i send wrong credentials to the server i.e same username as before then i get 400 FileNotFoundException. I need to interpret error details not only 400 code. Because if i send wrong details using curl from command line then i get error details also e.g this username already exists.
Here is my code to read response from the server. Actually i've tried two different methods but they all end up in same error which is 400(Bad Request) nothing else.
public static String readResponse(HttpURLConnection connection)
throws IOException, JSONException {
InputStream is = connection.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
StringBuilder response = new StringBuilder();
while((line = rd.readLine()) != null) {
response.append(line);
response.append('\r');
}
return response.toString();
}
public static String readResponseFromServer(HttpURLConnection connection) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader
(connection.getInputStream()));
String line = "";
StringBuilder stringBuilder = new StringBuilder();
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
return stringBuilder.toString();
}
In the above code there are two methods for reading response from the server.
And here is how i am using these methods to read response from the server
System.out.println("Server Response" + WebServiceHelpers.readResponseFromServer(urlConnection));
And i am also using the 2nd method which is readResponse() from the above code.
And here is the screenshot of curl command in which i am sending wrong details to the server and getting error details.
I've also tried this with HTTPIE and i am also getting the same response as using curl command i.e A user with that username already exists.
I need these error details in my Java code also. I have searched the internet but didn't found a solution.
Any suggestions?
Try this
public static String readResponse(HttpURLConnection connection)
throws IOException, JSONException {
int respCode = connection.getResponseCode();
InputStream is = null;
if (isErrorCode(respCode)) {
is = connection.getErrorStream();
} else if (connection.getErrorStream() != null) {
is = connection.getInputStream();
}
//FIXME: InputStreamReader must be constructed with right charset
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
StringBuilder response = new StringBuilder();
while((line = rd.readLine()) != null) {
response.append(line);
}
return response.toString();
}
Write isErrorCode method. It should interpret response code 400 as error and other codes as you need. Also notice fixme comment. When you are constructing InputStreamReader without a charset it uses default charset (UTF-8 if you don't provide file.encoding property) but correct way is to get charset from Content-Type response header and process response body with that encoding. Method for extracting charset from response may looks like this
private String getCharset(HttpURLConnection con) {
String charset = "";
String contentType = con.getContentType();
if (contentType != null) {
String[] values = contentType.split(";");
for (String value : values) {
String trimValue = value.trim();
if (trimValue.toLowerCase().startsWith("charset=")) {
charset = trimValue.substring("charset=".length());
}
}
}
if ("".equals(charset)) {
charset = "UTF-8";
}
return charset;
}
I have a javascript library that is sending a POST request to my Java servlet, but in the doPost method, I can't seem to get the contents of the request payload. In chrome Developer Tools, all the content is in the Request Payload section in the headers tab, and the content is there, and I know that the POST is being received by the doPost method, but it just comes up blank.
For the HttpServletRequest
object, what way can I get the data in the request payload?
Doing request.getParameter() or request.getAttributes()
both end up with no data
Simple answer:
Use getReader() to read the body of the request
More info:
There are two methods for reading the data in the body:
getReader() returns a BufferedReader that will allow you to read the body of the request.
getInputStream() returns a ServletInputStream if you need to read binary data.
Note from the docs: "[Either method] may be called to read the body, not both."
String payloadRequest = getBody(request);
Using this method
public static String getBody(HttpServletRequest request) throws IOException {
String body = null;
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
body = stringBuilder.toString();
return body;
}
You can use Buffer Reader from request to read
// Read from request
StringBuilder buffer = new StringBuilder();
BufferedReader reader = request.getReader();
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line);
buffer.append(System.lineSeparator());
}
String data = buffer.toString()
Java 8 streams
String body = request.getReader().lines()
.reduce("", (accumulator, actual) -> accumulator + actual);
With Apache Commons IO you can do this in one line.
IOUtils.toString(request.getReader())
If the contents of the body are a string in Java 8 you can do:
String body = request.getReader().lines().collect(Collectors.joining());
If you are able to send the payload in JSON, this is a most convenient way to read the playload:
Example data class:
public class Person {
String firstName;
String lastName;
// Getters and setters ...
}
Example payload (request body):
{ "firstName" : "John", "lastName" : "Doe" }
Code to read payload in servlet (requires com.google.gson.*):
Person person = new Gson().fromJson(request.getReader(), Person.class);
That's all. Nice, easy and clean. Don't forget to set the content-type header to application/json.
Using Java 8 try with resources:
StringBuilder stringBuilder = new StringBuilder();
try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(request.getInputStream()))) {
char[] charBuffer = new char[1024];
int bytesRead;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
}
You only need
request.getParameterMap()
for getting the POST and GET - Parameters.
The Method returns a Map<String,String[]>.
You can read the parameters in the Map by
Map<String, String[]> map = request.getParameterMap();
//Reading the Map
//Works for GET && POST Method
for(String paramName:map.keySet()) {
String[] paramValues = map.get(paramName);
//Get Values of Param Name
for(String valueOfParam:paramValues) {
//Output the Values
System.out.println("Value of Param with Name "+paramName+": "+valueOfParam);
}
}
This question already has answers here:
How to get HttpClient returning status code and response body?
(5 answers)
Closed 2 years ago.
I've just begun using Apache's HTTP Client library and noticed that there wasn't a built-in method of getting the HTTP response as a String. I'm just looking to get it as as String so that i can pass it to whatever parsing library I'm using.
What's the recommended way of getting the HTTP response as a String? Here's my code to make the request:
public String doGet(String strUrl, List<NameValuePair> lstParams) {
String strResponse = null;
try {
HttpGet htpGet = new HttpGet(strUrl);
htpGet.setEntity(new UrlEncodedFormEntity(lstParams));
DefaultHttpClient dhcClient = new DefaultHttpClient();
PersistentCookieStore pscStore = new PersistentCookieStore(this);
dhcClient.setCookieStore(pscStore);
HttpResponse resResponse = dhcClient.execute(htpGet);
//strResponse = getResponse(resResponse);
} catch (ClientProtocolException e) {
throw e;
} catch (IOException e) {
throw e;
}
return strResponse;
}
You can use EntityUtils#toString() for this.
// ...
HttpResponse response = client.execute(get);
String responseAsString = EntityUtils.toString(response.getEntity());
// ...
You need to consume the response body and get the response:
BufferedReader br = new BufferedReader(new InputStreamReader(httpresponse.getEntity().getContent()));
And then read it:
String readLine;
String responseBody = "";
while (((readLine = br.readLine()) != null)) {
responseBody += "\n" + readLine;
}
The responseBody now contains your response as string.
(Don't forget to close the BufferedReader in the end: br.close())
You can do something like:
Reader in = new BufferedReader(
new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
Using the reader you will be able to build your string. But if you are using SAX you can give the stream to the parser directly. This way you will not have to create the string and your memory footprint will be lower too.
In terms of conciseness of code it might be using the Fluent API like this:
import org.apache.http.client.fluent.Request;
[...]
String result = Request.Get(uri).execute().returnContent().asString();
The documentation warns though that this approach is not ideal in terms of memory consumption.
I'm working on Yahoo boss API. The URL supposed to return JSON, I need to store it in a string then parse it. http://developer.yahoo.com/java/howto-parseRestJava.html
My question: How can I save URL response in a string ??
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpResponse response = (HttpResponse) httpclient.execute(httpPostRequest);//send a request and receive a response
System.out.println("HTTPResponse received in [" + (System.currentTimeMillis()-t) + "ms]");
HttpEntity entity = response.getEntity();
if (entity != null) {
// Read the content stream
InputStream instream = entity.getContent();
// convert content stream to a String
String resultString= convertStreamToString(instream);
instream.close();
resultString = resultString.substring(1,resultString.length()-1); // remove wrapping "[" and "]"
and here is the function convertStreamToString
private static String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
Technically, you want to wrap an appropriately configured InputStreamReader around the URL InputStream and copy the Reader to a StringWriter (apache commons IO has a "copy Reader to String" utility method). However, in order to determine the correct character set for the InputStreamReader, you need to parse the ContentType header. In which case you might be better off working with a higher level library like apache commons HttpClient.
Or, you could wrap a JSONTokener around the URL InputStream and parse the JSONObject directly from the JSONTokener (although i'm not entirely sure how the tokener determines the correct character set, so you might be safer using something like HttpClient).
I have a program in Java where I retrieve contents from a database.
Now I have a form in the program, and what I want to do is, on the press of a button, some string (text) content retrieved from the database, should be sent over to a website that I'm hosting locally. The content so sent, should be displayed on the website when refreshed.
Can someone guide me as to how I can achieve this (the sending of data to be displayed over the website)?
Will appreciate a lot, if you could kindly show some sample snippets or give me a reference to some tutorial that can help.
---- Okay so i found a link to a snippet that's supposed to do this, but im unable to understand at this stage as to how exactly this snippet works...can someone please guide me into knowing this better ?
here's the code
try {
// Construct data
String data = URLEncoder.encode("key1", "UTF-8") + "=" + URLEncoder.encode("value1", "UTF-8");
data += "&" + URLEncoder.encode("key2", "UTF-8") + "=" + URLEncoder.encode("value2", "UTF-8");
// Send data
URL url = new URL("http://hostname:80/cgi");
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(data);
wr.flush();
// Get the response
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = rd.readLine()) != null) {
// Process line...
}
wr.close();
rd.close();
} catch (Exception e) {
}
I'm not sure on how you store and manage any of the records but from Java you can send a HTTP Post to the Url (In your case http://localhost/, probably).
Have a look at http://www.exampledepot.com/egs/java.net/post.html for a snippet on how to do this.
Your Website could then store the received information in a database and display it when you refresh.
Update heres the function
Just a side not this is by no means the best way to do this and I have no idea on how this scales but for simple solutions this has worked for me in the past.
/**
* Posts a Set of forms variables to the Remote HTTP Host
* #param url The URL to post to and read
* #param params The Parameters to post to the remote host
* #return The Content of the remote page and return null if no data was returned
*/
public String post(String url, Map<String, String> params) {
//Check if Valid URL
if(!url.toLowerCase().contains("http://")) return null;
StringBuilder bldr = new StringBuilder();
try {
//Build the post data
StringBuilder post_data = new StringBuilder();
//Build the posting variables from the map given
for (Iterator iter = params.entrySet().iterator(); iter.hasNext();) {
Map.Entry entry = (Map.Entry) iter.next();
String key = (String) entry.getKey();
String value = (String)entry.getValue();
if(key.length() > 0 && value.length() > 0) {
if(post_data.length() > 0) post_data.append("&");
post_data.append(URLEncoder.encode(key, "UTF-8"));
post_data.append("=");
post_data.append(URLEncoder.encode(value, "UTF-8"));
}
}
// Send data
URL remote_url = new URL(url);
URLConnection conn = remote_url.openConnection();
conn.setDoOutput(true);
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(post_data.toString());
wr.flush();
// Get the response
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
while ((inputLine = rd.readLine()) != null) {
bldr.append(inputLine);
}
wr.close();
rd.close();
} catch (Exception e) {
//Handle Error
}
return bldr.length() > 0 ? bldr.toString() : null;
}
You would then use the function as follows:
Map<String, String> params = new HashMap<String, String>();
params.put("var_a", "test");
params.put("var_b", "test");
params.put("var_c", "test");
String reponse = post("http://localhost/", params);
if(reponse == null) { /* error */ }
else {
System.out.println(reponse);
}
The big question is how will you authenticate the "update" from your Java program to your website?
You could easily write a handler on your website, say "/update" which saves the POST body (or value of a request parameter) to a file or other persistent store but how will you be sure that only you can set that value, instead of anybody who discovers it?