Im currently writing a servlet that should allow the user to write custom rest endpoints. The endpoints produce a RestResponse object which i am trying to convert into the final HTTPServletResponse Object.
The RestResponse contains a org.json.simple.JSONObject representing the Response Body. I now need to get this Object into the Body of of the HTTP Response.
My Idea is to use the PrintWriter of the HTTPServletResponse, According to the Debugger the entire JSONObject ends Up in the CharBuffer of the PrintWriter as it should, however in the final HTTP Response Body inside my Browser there is only the first character.
rest is my RestResponse object and http is my HTTPServletResponse Object (coming unchanged since handed into the doGet Method of the servlet)
I tried to use various different methods like:
if (rest.hasBody()) {
//TODO this somehow fails to write a valid JSON String to the HTTP Body
PrintWriter writer = http.getWriter();
rest.getBody().writeJSONString(writer);
//Here the proper json string ends in the buffer of the writer
writer.flush();
writer.close();
}
if (rest.hasBody()) {
//TODO this somehow fails to write a valid JSON String to the HTTP Body
PrintWriter writer = http.getWriter();
writer.write(rest.getBody.toJSONString());
//Here the proper json string ends in the buffer of the writer
writer.flush();
writer.close();
}
if (rest.hasBody()) {
//TODO this somehow fails to write a valid JSON String to the HTTP Body
PrintWriter writer = http.getWriter();
writer.append(rest.getBody.toJSONString());
//Here the proper json string ends in the buffer of the writer
writer.flush();
writer.close();
}
and so on, everything gives the same result
I've been debugging this for several hours now and i still didn't figure out whats wrong, does anybody have an idea?
Cheers
So my issue was that somehow i set http.setContentlength(variable) where variable accidentally was 1, therefor apparently the body will only contain the first character.
Related
First of all, I'm not sure whether this could be possible or not. I'm flushing bytes of data as PDF to the browser. Now the requirement is, I want to generate the pdf and also send one more extra object to be sent . Is it possible?
I've written something like this, but the result object is not getting as response.
YBUtil.GeneratePdf(response,documentBytes, "Bureau");
result.setStatus("SUCCESS");
return result; --> I want to pass this object as well
GeneratePdf method
public static void GeneratePdf(HttpServletResponse response, byte[] documentBytes, String fileName){
response.setHeader("Content-Disposition", "inline;filename="+fileName+".pdf");
response.setContentType("application/pdf");
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "must-revalidate, postcheck=0, pre-check=0");
response.setHeader("Pragma", "public");
response.setContentLength(documentBytes.length);
ServletOutputStream out = null;
try {
out = response.getOutputStream();
out.write(documentBytes);
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
In principle, this is more about the HTTP protocol than about Java.
HTTP is designed to send requests, with one optional request body sent along, and to receive a response in reaction, with one optional response body sent along. One. Not more than that.
When dealing with typical text stuff, you can send/respond a text-like format such as XML, JSON or web forms, that contain all the stuff you want it to contain. But when you want to receive/send a file, it's binary stuff and it must be sent as-is, alongside metadata that tell the file's type and name.
Now when you want to send/receive more than just a file, it looks like you're stuck. Well no. Look up multipart/form-data and realize you can use something similar for an HTTP response. Just like an email would.
Java can be programmed to respond with a multipart response. However, it is a bit of work to program, and I haven't really found an effective library that will success in helping me do it.
I have done this by sending a DTO object that will contain bytes(for pdf, this parsing of pdf is done on client side) and other values added to the DTO which are necessary.
I am using HttpsURLConnection to call a server and return the response returned from the HttpsURLConnection from my servlet. I am copying the response from HttpssURLConnection to HttpServletresponse using streams, copying bytes from the httpconnection response input stream to the response's output stream, checking the end by seeing if read returns < 0.
Following is the code for copying the response. The variable response is of type HttpServletResponse and the variable httpCon is of type HttpsURLConnection.
InputStream responseStream = httpCon.getInputStream();
if (responseStream != null)
{
OutputStream os = response.getOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = responseStream.read(buffer)) >= 0)
{
os.write(buffer, 0, len);
}
os.flush();
os.close();
}
On the client side, I am using python requests library to read the response.
What I am seeing that if I use the curl to test my servlet, I am getting the proper response json, response = u'{"key":"value"}'.
If i read it from the requests python, it is putting some extra characters in the response , the response looks like the following
response = u'b0\r\n{"key":"value"}\r\n0\r\n\r\n'
Both the strings are unicode. But the second one has extra characters.
Same resonse if I try from curl/Postman restclient, I am able to get it properly. But from python requests, it is not working. I tried another livetest library in python, with that also, it is not working and the response has same characters. I also tried to change the accept-encoding header but it did not have any effect.
Because of this, I am not able to parse the json.
I don't want to change the client to parse this kind of string.
Can I change something on the server so that it will work correctly?
Did the response contain the below header "Transfer-Encoding: chunked"?
The response should be in Chunked transfer encoding
https://en.wikipedia.org/wiki/Chunked_transfer_encoding.
In this case, you get \r\n0\r\n\r\n at the end of the response is as expected since it is terminating symbol of this encoding. I guest curl/Postman just help us to handle Chunked transfer encoding, so you can't find these chunked symbols.
I have a simple test client-server app. Client is html/javascript, server - Java Servlet
First of all I want to test request/response mechanism. Therefore I have used a simple code for cliet(jQuery):
$.get ("http://localhost:8081/TestProject/BasicServlet",
function(data) {
alert('Data:' +data);
}
);
And on the server side:
protected void doGet(HttpServletRequest req, HttpServletResponse res) ... {
String callBack = "TestCallback";
res.setContentType("text/html");
ServletOutputStream out = res.getOutputStream();
out.write(callBack.getBytes("UTF-8"));
out.flush();
}
So, Servlet catches request from client, but I have a problem with response, response header looks good, with character attributes, but I don't receive the callBack data
As response in Firebug I have 3 tabs, Header, Answer, HTML. Answer and HTML are empty
EDIT:
I have found a Problem: it was Access-Control-Allow-Origin violation.
Thanks for help !
As per the documentation in here
http://download.oracle.com/javaee/6/api/javax/servlet/ServletResponse.html#getOutputStream
is used for sending binary data. So my guess is that Content-Type header is set as some MIME type which is not recognized by jQuery. I suggest you check whether the Content-Type header is still "text/html" in the response using FireBug, or use
PrintWriter writer = res.getWriter();
writer.write(callBack);
writer.flush();
By the way, for sending textual data using PrintWriter is the recommended approach.
Try out.print() instead of out .write() you will get the response in your ajax call.
Question on HttpResponse object in servlets. Can the contents of a HttpResponse be only read once?
If so do I need to user a filter and some form of "javax.servlet.http.HttpServletResponseWrapper" in order to read the content of a HttpResponse object as I need to read its content to retrieve XML/JSON from the response? At the moment Im getting the below exception when I go to read the HttpResponse object.
Content has been consumed
at org.apache.http.entity.BasicHttpEntity.getContent(BasicHttpEntity.java:84)
Thanks,
John
This is not a problem in the server/servlet side. It's a problem in the client side. The servlet doesn't send HttpServletResponse object to the client or something, it just sends a byte stream only once. You just need to read it only once into a reuseable object such as a byte[] or String, depending on the actual content and and then reuse/copy exactly this object in the remnant of the code.
InputStream input = httpResponse.getEntity().getContent();
ByteArrayOutputStream output = new ByteArrayOutputStream(); // Or some file?
IOUtils.copy(input, output);
byte[] content = output.toByteArray();
// Now you can reuse content as many times as you want.
Do you want to read the content of the response or request? Usually we write the content of the response and do not read it, unless you have an special case here.
I'm writing my first JAVA servlet and I have a question.
May be it's important to say that my servlet will be called from Google Web Toolkit (AJAX)
First thing that I do is to create PrintWriter and start to write in it my JSON output
PrintWriter out = response.getWriter();
...
out.println("[");
out.println(" {");
out.println(" \"validation\" : {");
...
but what will happened if meanwhile I get an error condition?
What is the right way to return an error to client? (AJAX client)
Do I have to buffer my output (HOW?) and return error as JSON (instead of output)
or
I have to throw ServletException?
Just build the string in memory using for example StringBuilder. Do not write any character to the response yet until you're finished building the string. That's "buffering".
StringBuilder builder= new StringBuilder();
builder.append("[");
builder.append(" {");
builder.append(" \"validation\" : {");
// ...
// When finished:
response.getWriter().write(builder.toString());
When something fails in meanwhile, either throw ServletException (which will end up in a server default error page with status code 500), or use HttpServletResponse#sendError() to send a more specific error status. But generally, status code 500 is enough sign for XMLHttpRequest client that something failed at the server side.
try {
// Build and write JSON.
} catch (Exception e) {
throw new ServletException(e);
}
As #McDowell says, the correct way to deal with an error during request handling in a servlet is to set an HTTP status code in the response object.
But there is a catch.
The HTTP status code is actually passed in the first line of the HTTP response. And that gets written when the response is "committed", which typically happens when you call response.getOutputStream() or response.getWriter(). After that, you cannot change the status code.
The way to deal with it is to do one of the following:
Code your application so that errors don't happen during the generation of the response body.
Generate the response body to a buffer of some kind, and only open the response output stream / reader when you've built it completely. If there are errors during the body generation, you can set the HTTP status code and (if appropriate) send an alternative body containing an error message.
See the HTTP status codes. You can use HttpServletResponse.setStatus to set the response state (note also the constants defined by that class).