The method below is hit or miss if it parses the request properly...
Here is what the request looks like:
POST /addEvent/ HTTP/1.1
Host: localhost:1234
Content-Type: multipart/form-data; boundary=Boundary+0xAbCdEfGbOuNdArY
Accept-Encoding: gzip, deflate
Content-Length: 201
Accept-Language: en;q=1, fr;q=0.9, de;q=0.8, ja;q=0.7, nl;q=0.6, it;q=0.5
Accept: application/json
Connection: keep-alive
User-Agent: XXXXXXXXXXXXXXXXXX
--Boundary+0xAbCdEfGbOuNdArY
Content-Disposition: form-data; name="userInfo"
{ "user_id" : 1, "value" : "Water", "typeCode" : "Searched" }
Here is how we are extracting it now...
//Key where the request begins
String keyString = "\"userInfo\"";
//Get the index of the key
int end = bufferedJson.lastIndexOf("\"userInfo\"");
//Create substring at beginning of the json
String json = bufferedJson.substring(end+keyString.length(), bufferedJson.length());
//Convert json to feed item
Gson gson = new Gson();
Event eventItem = gson.fromJson(json, Event.class);
I get this error pretty often:
Expected BEGIN_OBJECT but was STRING at line 1 column 1
How can we parse this efficiently?
Use Apache HTTP Client 4 to read Http response body in a convenient way. If you need to marshall your json further to a java object then make use of jackson. Here is the sample code:
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
/**
* This example demonstrates the use of the {#link ResponseHandler} to simplify
* the process of processing the HTTP response and releasing associated resources.
*/
public class ClientWithResponseHandler {
public final static void main(String[] args) throws Exception {
HttpClient httpclient = new DefaultHttpClient();
try {
HttpGet httpget = new HttpGet("http://www.google.com/");
System.out.println("executing request " + httpget.getURI());
// Create a response handler
ResponseHandler<String> responseHandler = new BasicResponseHandler();
// Body contains your json stirng
String responseBody = httpclient.execute(httpget, responseHandler);
System.out.println("----------------------------------------");
System.out.println(responseBody);
System.out.println("----------------------------------------");
} finally {
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
}
}
To parse this better:
First, it seems like you're taking a "raw" HTTP POST request, and then reading it line by line using BufferedReader (your comment suggests this), this way you'll lose the new line chars; if you are going to do so, add a new line ("\n") every time you read a line to your final String, this way it doesn't lose the new lines and facilitates the things for the next step.
Now, with this final String, you can use this:
String json = null;
Pattern pattern = Pattern.compile("\n\n");
Matcher matcher = pattern.matcher(myString); // myString is the String you built from your header
if(matcher.find() && matcher.find()) {
json = myString.substring(matcher.start() + 2);
} else {
// Handle error: json string wasn't found
}
CAVEATS: this works if:
POST Request will always be multipart/form-data
There are not other parameters in the request
you STOP reading the request as soon as you find your json data
you included "\n" every time you read a line as I said in the first step
Personally I wouldn't read the raw HTTP header, I'd rather use Apache commons FileUpload or the like, but if your are going to do it this way, I think this is the less terrible solution.
You can use
gson().fromJson(request.getReader(), Event.class);
or
String json = request.getReader().readLine();
gson().fromJson(json, Event.class);
Related
Trying to get parameters from a PUT request using HttpServlet#doPut:
public void doPut(HttpServletRequest request, HttpServletResponse response) {
String name = request.getParameter("name");
// name is null
}
Using curl to send the request:
curl -X PUT \
--data "name=batman" \
--header "Content-Type: text/plain" http://localhost:8080/sample.html
works fine with using doGet and GET curl request. Am I missing something?
Based on comments and further research I realized that the Servlet cannot assume anything about the data being put onto the server and therefore, will not parse name/value pairs.
The following solution seems to be the proper way to handle any data passed via PUT, and can be parsed as XML, Name/Value, or whatever.
BufferedReader br = new BufferedReader(new InputStreamReader(req.getInputStream());
String data = br.readLine();
Unlike in doGet() and doPost() methods, we are not able to get the request parameters using the getParameter() method in doPut() and doDelete() methods. We need to retrieve them manually from the input stream.
The following method retrieves request parameters and returns them in a map:
public static Map<String, String> getParameterMap(HttpServletRequest request) {
BufferedReader br = null;
Map<String, String> dataMap = null;
try {
InputStreamReader reader = new InputStreamReader(
request.getInputStream());
br = new BufferedReader(reader);
String data = br.readLine();
dataMap = Splitter.on('&')
.trimResults()
.withKeyValueSeparator(
Splitter.on('=')
.limit(2)
.trimResults())
.split(data);
return dataMap;
} catch (IOException ex) {
Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
} finally {
if (br != null) {
try {
br.close();
} catch (IOException ex) {
Logger.getLogger(Utils.class.getName()).log(Level.WARNING, null, ex);
}
}
}
return dataMap;
}
The example uses Google's Guava library to parse the parameters.
For a complete example containing doGet(), doPost(), doPut() and doDelete() methods, you can read my Using jsGrid tutorial.
What do you mean by doPut() is not working? As far as I know, it doesn't work like doGet() or doPost(), where you have request parameters and stuff.
PUT can be used to put something on the server. In particular, the PUT operation allows a client to place a file on the server and is similar to sending a file by FTP. Check out this example, I found on JGuru.
->GET /file.dat HTTP/1.1
<-HTTP/1.1 404 Not Found
->PUT /file.dat HTTP/1.1
Content-Length: 6
Content-Type: text/plain
Hello!
<-HTTP/1.1 200 OK
->GET /file.dat HTTP/1.1
<-HTTP/1.1 200 OK
Content-Length: 6
Content-Type: text/plain
Hello!
Pseudo code:
import okhttp3.*;
private final OkHttpClient mClient = new OkHttpClient.Builder().readTimeout(45, TimeUnit.SECONDS).build();
Request request = new Request.Builder().url(createUrl(path, parameters)).build();
okhttp3.Response response = mClient.newCall(request).execute();
String body = response.body().string();
System.out.print(body);
My HTTP server does not send any newlines (\n) in the BODY of the message (and I verified this using curl); when I print out the received response body from okhttp, I always see \n. Any ideas on how to let okhttp know not to add \n?
I am trying to transfer form data from an Android application to a NodeJs server.
My client code is the following (the strings that can contain UTF-8 characters are the values of params):
final HttpPost post = new HttpPost(url);
final MultipartEntityBuilder mpb = MultipartEntityBuilder.create()
.setCharset(Charset.forName("UTF-8")) // tried with or without this line
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); // tried with or without this line
for (final Entry<String, String> e : params.entrySet()) {
mpb.addTextBody(e.getKey(), e.getValue());
}
post.setEntity(mpb.build());
final HttpClient httpClient = new DefaultHttpClient();
final HttpResponse response = httpClient.execute(request);
And my server code is the following:
app.post('/accesspoint', function(req, res) {
var body = req.body;
var form = new formidable.IncomingForm();
form.encoding = 'utf-8';
form.parse(req, function(err, fields, files) {
console.log(fields);
...
When my input java params has a value containing an UTF-8 character, the log I get server side prints the corresponding value without this character, so it is kind of swallowed at some point. For instance if my input string is "ê", then my server log will print a "" value.
I use a multipart form as I read that it was the best way to send data that can contain non-ASCII characters. Formidable is also apparently the best node package to handle form that can contain UTF-8 characters.
My client side uses Apache HttpClient 4.3.3.
What am I doing wrong?
Ok so I tested with a simple query and the key value ("foo","[ê]") looked at the headers and I saw that my query was still using ISO-8859-1
Content-Disposition: form-data; name="foo"
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8bit
[]
in contradiction to my builder parameter.
I found the solution via https://stackoverflow.com/a/21020435/592392 and changed my code to:
for (final Entry<String, String> e : params.entrySet()) {
mpb.addTextBody(e.getKey(), e.getValue(), ContentType.create("text/plain", Charset.forName("UTF-8")));
}
And now the server gets the UTF8 chars :)
Anyway, the form builder is quite misleading in my opinion.
I receive a post request from client. This request contains some json data which I want to part on the server side. I have created the server using httpcore. HttpRequestHandler is used for handling the request. Here is the code I thought would work
HttpEntity entity = ((HttpEntityEnclosingRequest)request).getEntity();
InputStream inputStream = entity.getContent();
String str = inputStream.toString();
System.out.println("Post contents: " + str);*/
But I cant seem to find a way to get the body of the request using the HttpRequest object. How can I extract the body from the request object ? Thanks
You should use EntityUtils and it's toString method:
String str = EntityUtils.toString(entity);
getContent returnes stream and you need to read all data from it manually using e.g. BufferedReader. But EntityUtils does it for you.
You can't use toString on stream, because it returns string representation of the object itself not it's data.
One more thing: AFAIK GET requests can't contain body so it seems you get POST request from client.
... and for MultipartEntity use this:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
entity.writeTo(baos);
} catch (IOException e) {
e.printStackTrace();
}
String text = new String(baos.toByteArray());
Trying to get parameters from a PUT request using HttpServlet#doPut:
public void doPut(HttpServletRequest request, HttpServletResponse response) {
String name = request.getParameter("name");
// name is null
}
Using curl to send the request:
curl -X PUT \
--data "name=batman" \
--header "Content-Type: text/plain" http://localhost:8080/sample.html
works fine with using doGet and GET curl request. Am I missing something?
Based on comments and further research I realized that the Servlet cannot assume anything about the data being put onto the server and therefore, will not parse name/value pairs.
The following solution seems to be the proper way to handle any data passed via PUT, and can be parsed as XML, Name/Value, or whatever.
BufferedReader br = new BufferedReader(new InputStreamReader(req.getInputStream());
String data = br.readLine();
Unlike in doGet() and doPost() methods, we are not able to get the request parameters using the getParameter() method in doPut() and doDelete() methods. We need to retrieve them manually from the input stream.
The following method retrieves request parameters and returns them in a map:
public static Map<String, String> getParameterMap(HttpServletRequest request) {
BufferedReader br = null;
Map<String, String> dataMap = null;
try {
InputStreamReader reader = new InputStreamReader(
request.getInputStream());
br = new BufferedReader(reader);
String data = br.readLine();
dataMap = Splitter.on('&')
.trimResults()
.withKeyValueSeparator(
Splitter.on('=')
.limit(2)
.trimResults())
.split(data);
return dataMap;
} catch (IOException ex) {
Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
} finally {
if (br != null) {
try {
br.close();
} catch (IOException ex) {
Logger.getLogger(Utils.class.getName()).log(Level.WARNING, null, ex);
}
}
}
return dataMap;
}
The example uses Google's Guava library to parse the parameters.
For a complete example containing doGet(), doPost(), doPut() and doDelete() methods, you can read my Using jsGrid tutorial.
What do you mean by doPut() is not working? As far as I know, it doesn't work like doGet() or doPost(), where you have request parameters and stuff.
PUT can be used to put something on the server. In particular, the PUT operation allows a client to place a file on the server and is similar to sending a file by FTP. Check out this example, I found on JGuru.
->GET /file.dat HTTP/1.1
<-HTTP/1.1 404 Not Found
->PUT /file.dat HTTP/1.1
Content-Length: 6
Content-Type: text/plain
Hello!
<-HTTP/1.1 200 OK
->GET /file.dat HTTP/1.1
<-HTTP/1.1 200 OK
Content-Length: 6
Content-Type: text/plain
Hello!