I have a servlet named EditPhotos which, believe it or not, is used for editing the photos associated with a certain item on a web design I am developing. The URL path to edit a photo is [[SITEROOT]]/EditPhotos/[[ITEMNAME]].
When you go to this path (GET), the page loads fine. You can then click on a 'delete' link that POSTs to the same page, telling it to delete the photo. The servlet receives this delete command properly and successfully deletes the photo. It then sends a redirect back to the first page (GET).
For some reason, this redirect fails. I don't know how or why, but using the HTTPFox plugin for firefox, I see that the POST request receives 0 bytes in response and has the code NS_BINDING_ABORTED.
The code I am using to send the redirect, is the same code I have used throughout the website to send redirects:
response.sendRedirect(Constants.SITE_ROOT + "EditPhotos/" + itemURL);
I have checked the final URL that the redirect sends, and it is definitely correct, but the browser never receives the redirect. Why?
Read the server logs. Do you see IllegalStateException: response already committed with the sendRedirect() call in the trace?
If so, then that means that the redirect failed because the response headers are already been sent. Ensure that you aren't touching the HttpServletResponse at all before calling the sendRedirect(). A redirect namely exist of basically a Location response header with the new URL as value.
If not, then you're probably handling the request using JavaScript which in turn failed to handle the new location.
If neither is the case or you still cannot figure it, then we'd be interested in the smallest possible copy'n'pasteable code snippet which reproduces exactly this problem. Update then your question to include it.
Update as per the comments, the culprit is indeed in JavaScript. A redirect on a XMLHttpRequest POST isn't going to work. Are you using homegrown XMLHttpRequest functions or a library around it like as jQuery? If jQuery, please read this question carefully. It boils down to that you need to return a specific response and then let JS/jQuery do the new window.location itself.
Turns out that it was the JavaScript I was using to send the POST that was the problem.
I originally had this:
Delete
And everything got fixed when I changed it to this:
Delete
The deletePhoto function is:
function deletePhoto(photoID) {
doPost(document.URL, {'action':'delete', 'id':photoID});
}
function doPost(path, params) {
var form = document.createElement("form");
form.setAttribute("method", "POST");
form.setAttribute("action", path);
for(var key in params) {
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", key);
hiddenField.setAttribute("value", params[key]);
form.appendChild(hiddenField);
}
document.body.appendChild(form);
form.submit();
}
Related
My scenario is like this:
I'm building a website where I'm posting an ad regarding a topic. So, after the form filling of ad, the request goes to a REST service class as:
http://localhost:8080/cloudproject/postadvaction?title=tution&tag=tution&description=tution+%401000+%2F+month&category=TUTOR&location=indore
Here, the details of ad go in the database which is MongoDB. After all of this is done I'm redirecting to the profile page of user using Viewable model of jersey, where he can see all the ads posted by him. It is done as:
return new Viewable("/profile.jsp");
After this the response is redirected to profile page of the user.
But the problem is that, on redirecting the response to simply profile.jsp, the URL in the address bar has not changed to http://localhost:8080/profile.jsp, instead, it has remained the same as mentioned above. So, when user refreshes the page, the request of same ad post triggers and the whole process is followed again. Since, database is MongoDB, same ad is stored twice in it and same is displayed on the profile page of user with 2 identical ads.
So, how can I redirect to profile page without having the address of servlet in address bar?
Update: The question is related to PRG technique & Duplicate Form Submissions and not to just redirection.
See Post/Redirect/Get
When a web form is submitted to a server through an HTTP POST request, a web user that attempts to refresh the server response in certain user agents can cause the contents of the original HTTP POST request to be resubmitted, possibly causing undesired results, such as a duplicate web purchase.
To avoid this problem, many web developers use the PRG pattern[1] — instead of returning a web page directly, the POST operation returns a redirection command. The HTTP 1.1 specification introduced the HTTP 303 ("See other") response code to ensure that in this situation, the web user's browser can safely refresh the server response without causing the initial HTTP POST request to be resubmitted. However most common commercial applications in use today (new and old alike) still continue to issue HTTP 302 ("Found") responses in these situations.
With Jersey you can use
Response.seeOther(URI) - Create a new ResponseBuilder for a redirection. Used in the redirect-after-POST (aka POST/redirect/GET) pattern.
You just need to change your method signature to return a Response and return the built Response
return Response.seeOther(URI.create(...)).build();
Also stated about the URI parameter
the redirection URI. If a relative URI is supplied it will be converted into an absolute URI by resolving it relative to the base URI of the application (see UriInfo.getBaseUri()).
In one of my #RequestMapping POST methods I need to return HttpServletResponse (which is an xml file) and I want to refresh the view. Normally I would just return path but in this case it gets appended to the xml file which is being downloaded by user.
Is there any way to close and send response first and then generate(refresh) view?
I would say no, it's not. Not a 100 percent sure though. You could try to send the file and also set the redirect header in your response. I didn't try it just now but I guess you will just be redirected. Really depends on the browser though. A browser could decide to still download the file.
Once you sent the response a new request needs to be generated by the client, so there is no way to close it server-side and just create a new one.
I would suggest a solution using Javascript. Either AJAX or just setting the current location twice (first the download, then the new view). I'm not sure, I guess via location.href
Let me know if you need an actual code example, as it would take me some time to manufacture something.
I making a web crawler and there are some pages that redirect to other. How I get the page that the original page redirected?
In some sites like xtema.com.br, I can get the url of redirection using the HttpURLConnection class with the getHeaderField("Location") method, but in others like visa.com.br, the redirection is made using javascript or another way and this method returns null.
There is some way to always get the page and the url resulting of redirection? The original page without the redirection is not important.
Thanks, and sorry for bad english.
EDIT: Using httpConn.setInstanceFollowRedirects(true) to follow the redirections and returning the URL with httpConn.getURL worked, but I have two issues.
1: The httpConn.getURL only will return the actual url of the redirected page if I call httpConn.getDate before. If I dont this, it will return the original URL before the redirections.
2: Some sites like visa.com.br get the answer 200, but if I open then in the web browser, I see another page.
Eg.: my program - visa.com.br - answer 200 (no redirections)
web broser - visa.com.br/go/principal.aspx - html code different of the version that i get in my program
Use HttpURLConnection, it follows redirects by default.
In case you want to see the redirected URL, you'll have to do:
httpConn.setInstanceFollowRedirects( false );
httpConn.connect();
int responseCode = httpConn.getResponseCode();
while ((responseCode / 100) == 3) { /* codes 3XX are redirections */
String newLocationHeader = httpConn.getHeaderField( "Location" );
/* open a new connection and get the content for the URL newLocationHeader */
/* ... */
responseCode = httpConn.getResponseCode();
/* do it until you get some code that is not a redirection */
}
You can't easily get javascript redirection. And HTTP redirection is handled by default by the HttpURLConnection. What you can do is, search the page contents for several keywords:
the meta refresh tag
document.location=, window.location= and both with .href=
But this does not guarantee anything. People might be calling javascript functions from external js files and you will pretty much need to fetch resources and parse javascript, which you aren't willing to do, I guess.
I ended up using Apache's HTTP client. Just another option.
As I understand it and have used it, AJAX is used to make requests from the client to the server and to then update a HTML DIV on the client with new content.
However, I want to use AJAX from a client to a servlet to verify the existence of a URL. If the result is bad, I can set an error message in the servlet and return it to the client page for display.
But does anyone know if, in the case of a positive result, I can have my servlet automatically display another (the next) page to the user? Or should that request be triggered by Javascript on the client when the positive results is received.
Thanks
Mr Morgan.
Since your ajax call is executed in the background the result returned by the servlet, returns to the ajax call, which should then act accordingly to the result. e.g. trigger the display of another page. (Which could have been already in the ajax response and then you can show it in a div or iframe or ...)
As per the W3 specification, XMLHttpRequest forces the webbrowser to the new location when the server returns a fullworthy 301/302 redirect and the Same Origin Policy of the new request is met. This however fails in certain browsers like certain Google Chrome versions.
To achieve best crossbrowser result, also when the redirected URL doesn't met the Same Origin Policy rules, you would like to change the location in JavaScript side instead. You can eventually let your servlet send the status and the desired new URL. E.g.
Map<String, Object> map = new HashMap<String, Object>();
map.put("redirect", true);
map.put("location", "http://stackoverflow.com");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
resposne.getWriter().write(new Gson().toJson(map));
(that Gson is by the way Google Gson which eases converting Java Objects to JSON)
and then in the Ajax success callback handler in JS:
if (response.redirect) {
window.location = response.location;
}
In your success call back (on client), set the self.location.href to new URL.
HTML is a "pull" technology: Nothing gets displayed in the browser that the browser hasn't previously requested from the server.
Hence, you don't have a chance to "make the servlet automatically display a different page." You have to talk your browser (from JavaScript) into requesting a different page.
I have Application written with GWT 1.7. I have one page where I upload file to the remote server that is on different domain. So, when I do Post to the server files goes to the server but when it's time to get response I'm getting null in following function:
Servlet:
...
resp.setStatus(HttpServletResponse.SC_CREATED);
resp.getWriter().print("The file was created successfully.");
resp.flushBuffer();
...
GWT:
form.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() {
public void onSubmitComplete(SubmitCompleteEvent event) {
Window.alert(event.getResults());
}
Javadoc for event.getResults() said following:
Returns: the result html, or null if
there was an error reading it #tip The
result html can be null as a result of
submitting a form to a different
domain.
This is the code example that I tried to follow. It works as is, but when I'm calling my servlet the response is null.
By the way I tried to use Firebug to see Headers and it seems to me that servlet is sending response back. I think it's just GWT does not like it. Is there any work around for this so I can get my response in GWT?
Thanks
Not to state the obvious but it says right in the quote you posted what is wrong:
The result html can be null as a result of submitting a form to a different domain.
It looks like the code sample you link to is on the same domain so it's not violating the same origin policy for the browser.
There's this workaround but it seems to be for earlier version of GWT and only works for Firefox.