Does a HttpServlet have to respond to a request? - java

I have several servlets that do things server side. On a few I just encode some unnecessary data and send it back, which seems pointless. Do you have to respond ? What happens when you just say return ? I've done that before and nothing seems to go wrong but I am relatively new to servlets. Are there consequences for simply returning that go above my head ? And what exactly happens when you return;
if(request.getParameter("name").equals("saveusedcards")) {
String sessId = request.getSession().getId();
//encode request with confirmation that cards were successfully updated
if(usersUpdatedCards.get(sessId).isEmpty()){
//no cards were seen
}
boolean success = DataDAO.updateCards(usersUpdatedCards.get(sessId));
if(success){
System.out.println("Data base update successfull!");
String responseMessage = new Gson().toJson("card successfully udpated");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
System.out.println("updated cards response message: "+responseMessage);
response.getWriter().write(responseMessage);
return;
} else {
System.out.println("Data base update failed...");
String responseMessage = new Gson().toJson("card was not successfully updated");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
System.out.println("updated cards response message: "+responseMessage);
response.getWriter().write(responseMessage);
return;
}
}

The servlet must produce an HTTP response for the client, however it is perfectly acceptable to return no content in the response body. When doing so your servlet should make this clear to the client by sending a response code of 204 (no content). Reference: https://httpstatuses.com/204
Here is an example of how you would set the response code from the doGet method. You could do the same from doPost or service methods.
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// Do whatever work you need to do here...
res.setStatus(HttpServletResponse. SC_NO_CONTENT); // This returns a 204
}

Related

Can't POST JSON using Volley

I've searched a lot but can't find out what's happening. I wrote many variations of this code and here is the most recent one.
Android code
private static void post(#NonNull String url,
#NonNull Context context,
#NonNull final JSONObject jsonRequest,
#NonNull final ServerConnectionAdapter serverConnectionAdapter){
Log.d(TAG, "post: URL = " + url);
RequestQueue queue = Volley.newRequestQueue(context);
JsonObjectRequest postRequest = new JsonObjectRequest(
Request.Method.POST,
url,
jsonRequest,
serverConnectionAdapter,
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
serverConnectionAdapter.onErrorResponse(null, error);
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> map = new HashMap<>();
// map.put("user", json.toString());
map.put("user", "{\"id\":-1,\"name\":\"Gustavo Araujo\"}");
return map;
}
};
queue.add(postRequest);
}
Server (Java) code
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("doPost");
System.out.println("REQUEST: ");
for (Map.Entry<String, String[]> e : request.getParameterMap().entrySet()){
System.out.print(" ");
System.out.println(e.getKey() + ": " + java.util.Arrays.toString(e.getValue()));
}
System.out.println("end");
}
doPost method output
doPost
REQUEST:
end
I've been starring my screen for so long that I think I can't find where is the error. I did find many examples, with and without the getParams(). I tried both, and didn't change anything.
The ServerConnectionAdapter is an abstract class that I created to unify the response with the error listener. I am sure that it is not the problem because it does work flawlessly with the GETs that I have.
The String url also can't be wrong (otherwise the server wouldn't have been triggered.
The jsonRequest also isn't the problem because I already used null there and didn't change the results at all.
As I said, I've been starring this code for hours, all my assumptions may be completely wrong, that's why I'm asking for help.
The error photo you posted in comment in telling me that your request was successful, there isn't any issue from mobile side. The issue is from server side. Because when you are making the request it's going on server but your server is not returning any proper Json. It's returning nothing that's why you are getting that exception. Android request needs a Json in return but you are server is not returning that.
There is a possibility that the issue can be from app side and the cause for that is that maybe you are not sending the proper parameters to server. But as far as I can see, the main issue is from server side. Because all these exceptions are not handled on server side. Like when the parameters are wrong it should return a json with message telling you that the parameters are wrong.
I was doing it wrong. The way that I wrote the doPost method I was reaching the request parametes, like when you access http://localhost:8080/something?key=value what is not what I intend to do.
I needed to read the body of the request. To do so, in Java, it should be as the code below:
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Get the body of the request
BufferedReader reader = request.getReader();
// Print each line
String line;
while ((line = reader.readLine()) != null){
System.out.println(line);
}
}
Thank you for Zohaib Hassan for trying to help.

GWT HTTP request response code 0 with CORS working

I am using GWT 2.4 to build an application that runs entirely client-side and uses a web service that I control but is hosted on a different server. On this Java Servlet web service, I have implemented doOptions like so:
protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "POST, GET");
}
And client-side in GWT I submit a request the standard way, e.g.
public static void makeHttpGetRequest(String query, RequestCallback callback) {
String url = "http://example.webservice.com/endpoint" + "?q=" + query;
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, URL.encode(url));
try {
builder.sendRequest(query, callback);
} catch (RequestException e) {
Window.alert("Server encountered an error: \n" + e.getMessage());
e.printStackTrace();
}
}
And then my callback implements onResponseReceived like this:
#Override
public void onResponseReceived(Request request, Response response) {
if (response.getStatusCode() == 200) {
System.out.println("HTTP request successful, received "
+ response.getText());
processResponse(response.getText());
} else {
System.out.println("HTTP error code " +
response.getStatusCode() + ":" +
response.getStatusText());
}
}
Whenever I run the application in late versions of Chrome or Firefox and send a request, onResponseReceived is called but the response code is 0 and there is no error message. Research indicates that most other instances of this problem arise from SOP restrictions. However, when looking at the HTTP traffic in Fiddler I see that when this is executed, the browser is indeed sending the expected HTTP request, and the web service is indeed returning the expected response, with a 200 response code. Somehow, the browser just isn't handling it properly.
Update: when I look at the traffic in Fiddler, it indicates that the request is sent and a response is received, but when I look at the same request in Chrome's developer console it shows that the request is 'canceled'. If the request is actually happening, what does that mean in this context?
Has anyone run across this problem? Any suggestions on what may be going on?
Error code 0 means that the CORS has been aborted, check that your servlet implementation is all right, I think you have to send Allow instead of Access-Control-Allow-Methods, and also you have to add the Access-Control-Allow-Headers since GWT adds extra headers to ajax requests.
Try this implementation from the gwt-query example which works fine:
private static final String ALLOWED_DOMAINS_REGEXP = ".*";
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
String origin = req.getHeader("Origin");
if (origin != null && origin.matches(ALLOWED_DOMAINS_REGEXP)) {
resp.addHeader("Access-Control-Allow-Origin", origin);
resp.setHeader("Allow", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS");
if (origin != null) {
String headers = req.getHeader("Access-Control-Request-Headers");
String method = req.getHeader("Access-Control-Request-Method");
resp.addHeader("Access-Control-Allow-Methods", method);
resp.addHeader("Access-Control-Allow-Headers", headers);
resp.setContentType("text/plain");
}
}
I would rather a filter instead a servlet, like in the link above is explained, though.

Why the response.sendRedirect() in servlet doesn't work after receiving the post request of JQuery?

In the blog-edit.html, JQuery was used to send the post request to the sever side(java servlet).
$("#btn").click(function() {
$.post("/blog/handler",{"content":$('#textarea').val()},
function(data){
alert("Data Loaded: " + data);
if(data.toString().length>1){
alert("Saved!")
}else{
alert("Failed!")
}
})
In the server side:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String content = request.getParameter("content");
System.out.println(content);
response.sendRedirect("/blog/list");
return;
}
What I saw is the server side is printing the content from the html, and the alert window pops up to say "Saved!". But the redirect function doesn't work
After searching I have no choice but to use jquery to redirect:
if(data.toString().length>1){
alert("Saved!")
window.location.replace("/blog/list")
}
it works, but it's not what i want
please help
While using ajax. you can not execute server side redirect.
However, there are better way how to redirect on client in such a scenario.
See Here

response.sendRedirect() in Servlet not working correctly after file upload

I have a web application with a simple upload function. The idea is to allow user select a file and upon successfully upload, redirect to index.jsp.
However, although the file got uploaded, the response.redirect is not working. After a successfully upload, the page doesn't get redirected. It just stays there. The weird thing is that I can see it is processing the index.jsp from the tomcat server log even though it doesn;t get redirected.
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//processRequest(request, response);
boolean status=false;
if (!ServletFileUpload.isMultipartContent(request)) {
throw new IllegalArgumentException("Request is not multipart, please 'multipart/form-data' enctype for your form.");
}
ServletFileUpload uploadHandler = new ServletFileUpload(new DiskFileItemFactory());
PrintWriter writer = response.getWriter();
response.setContentType("text/plain");
try {
List<FileItem> items = uploadHandler.parseRequest(request);
for (FileItem item : items) {
if (!item.isFormField()) {
File file = new File(getServletContext().getRealPath("/WEB-INF/upload"), item.getName());
item.write(file);
writer.write("{\"name\":\"" + item.getName() + "\",\"type\":\"" + item.getContentType() + "\",\"size\":\"" + item.getSize() + "\"}");
}
}
//redirect to index.jsp if successfully
redirect(request, response);
} catch (FileUploadException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
writer.close();
}
}
The redirect method:
private void redirect(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.getRequestDispatcher("/index.jsp").forward(request, response);
}
The file upload plugin is from https://aquantum-demo.appspot.com/file-upload
I used the front-end and developed the upload event handler using java apache fileupload. Everything works fine except the redirect part.
The application.js file which handles the JSON returns:
$(function () {
// Initialize jQuery File Upload (Extended User Interface Version):
$('#file_upload').fileUploadUIX();
// Load existing files:
$.getJSON($('#file_upload').fileUploadUIX('option', 'url'), function (files) {
var options = $('#file_upload').fileUploadUIX('option');
options.adjustMaxNumberOfFiles(-files.length);
$.each(files, function (index, file) {
options.buildDownloadRow(file, options)
.appendTo(options.downloadTable).fadeIn();
});
});
});
Any ideas?
You're attempting to send two responses on a single request. One with JSON data in the response body and one which redirects the response to another request. This is not going to work. You can send only one response back per request. A redirect requires an untouched (uncommitted) response body, otherwise the redirect will just fail with IllegalStateException: response already committed in the server logs.
You need to move the redirect call from the servlet code to JavaScript code. Get rid of the redirect() line in the servlet and add the following line as the last line of the $.getJSON() callback function.
window.location = '/index.jsp';
This way JavaScript will take care of the redirect.

Use GZIP, JSON responses and JQuery

However, I want to compress my responses with GZIP wheren possible. I tried using the Compression filter code available for free download in the headfirst site. It works great for html, images, css and javascript.
I post the filter next. It checks if GZIP is an accepted encoding and it adds gzip as Content-Encoding. See: wrappedResp.setHeader("Content-Encoding", "gzip");
public class CompressionFilter implements Filter {
private ServletContext ctx;
private FilterConfig cfg;
/**
* The init method saves the config object and a quick reference to the
* servlet context object (for logging purposes).
*/
public void init(FilterConfig cfg)
throws ServletException {
this.cfg = cfg;
ctx = cfg.getServletContext();
//ctx.log(cfg.getFilterName() + " initialized.");
}
/**
* The heart of this filter wraps the response object with a Decorator
* that wraps the output stream with a compression I/O stream.
* Compression of the output stream is only performed if and only if
* the client includes an Accept-Encoding header (specifically, for gzip).
*/
public void doFilter(ServletRequest req,
ServletResponse resp,
FilterChain fc)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
// Dose the client accept GZIP compression?
String valid_encodings = request.getHeader("Accept-Encoding");
if ( (valid_encodings != null) && (valid_encodings.indexOf("gzip") > -1) ) {
// Then wrap the response object with a compression wrapper
// We'll look at this class in a minute.
CompressionResponseWrapper wrappedResp = new CompressionResponseWrapper(response);
// Declare that the response content is being GZIP encoded.
wrappedResp.setHeader("Content-Encoding", "gzip");
// Chain to the next component (thus processing the request)
fc.doFilter(request, wrappedResp);
// A GZIP compression stream must be "finished" which also
// flushes the GZIP stream buffer which sends all of its
// data to the original response stream.
GZIPOutputStream gzos = wrappedResp.getGZIPOutputStream();
gzos.finish();
// The container handles the rest of the work.
//ctx.log(cfg.getFilterName() + ": finished the request.");
} else {
fc.doFilter(request, response);
//ctx.log(cfg.getFilterName() + ": no encoding performed.");
}
}
public void destroy() {
// nulling out my instance variables
cfg = null;
ctx = null;
}
}
I was using the next code to send JSON responses in Struts web application.
public ActionForward get(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
JSONObject json = // Do some logic here
RequestUtils.populateWithJSON(response, json);
return null;
}
public static void populateWithJSON(HttpServletResponse response,JSONObject json) {
if(json!=null) {
response.setContentType("text/x-json;charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
try {
response.getWriter().write(json.toString());
} catch (IOException e) {
throw new ApplicationException("IOException in populateWithJSON", e);
}
}
}
It works fine without compression but if I compress JSON responses, I can not see my JSON objects anymore. I handle JSON Ajax calls with JQuery with code snippets as follows:
$.post(url,parameters, function(json) {
// Do some DOM manipulation with the data contained in the JSON Object
}, "json");
If I see the response with Firebug it is empty.
Should I refractor my compression filter to skip compression in JSON responses? or there is a workaround to this?
For me, it looks like JQuery does not recognize the response as JSON because I am adding the Gzip compression.
If I see the response with Firebug it
is empty.
There's your clue - it's not a JQuery problem, it's server-side. (I'm afraid I can't help you with that, other than to suggest you stop looking at the client-side)
There's no problem gzipping ajax responses - if you can't see the response in Firebug, then JQuery can't see it either.
you have to add one more header "content-encoding: gzip" if you are compressing it.
Have you tried with an explicit java-based client to ensure it's a problem with jQuery or browser? If java client fails, something is wrong with server response.
But I am guessing that whereas browser can deal with uncompression with direct requests, this is perhaps not applied to Ajax calls.
It's an interesting question, I hope we'll get a more definitive answer. :)

Categories

Resources