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.
Related
I am working with a web framework (uPortal) that is handling errors by just throwing an exception and then hanging. The framework works by rendering XML into HTML. When there is an exception, the browser recieves rendered content up to the XML template element that is failing, and then the browser just sits and waits for a timeout. Our team's theory is that the content is sent before the error occurs, which surprised me. Other frameworks I've worked with seem to finish rendering before sending content.
My question is, is there a way to redirect the browser after content has already been sent? In this case, we are in the middle of rendering the content of a <script> tag, but the error could occur potentially anywhere in the html.
My only current thought is to inject some javascript at the top of the page, and to try to change the framework's behavior to fail quickly and close the connection and add </body> and </html> tags when an error occurs. Then the above mentioned javascript would run on pageload and detect if the entire page's content was there and do a client-side redirect if not. Maybe it could look for a special hidden div at the bottom of the page.
Are there any examples of frameworks solving this problem differently or of people using similar framework working around this issue?
You must either capture the error, or capture the output in a buffer. If you can handle the exception, you can probably print a simple script tag like
<script> window.location.href = 'some_new_url';</script>
If the browser understands the doctype to be something related to HTML, it will execute that tag.
If you can capture the output in a buffer, when you handle the error you can decide to send an HTTP redirect to the browser and destroy the output buffer up to that point.
As for other frameowrks, in PHP, you can simply enable output buffering with ob_start(), which won't start sending content until the request is fully completed.
I don't know that framework, but
In http, every response has a response-code associated with it. Since the page is already half-way transferred / rendered that status code (usually "200") was sent (and received) already.
There's no way for the browser to accept another response code (like "301" for redirect) for the same response! Also the server is not able to send another response code, because the original response code was already commited and sent to the client.
Your description of the error and knowledge of the http-protocol implies that there is probably some implementation error in the framework / server components used, OR it was done deliberatly, risking the situation that you are in now...
to redirect a page , you need to set redirect information in header. but you can write header once you start writing content ( may be header is already received by client by the time you compete writing whole document )
But, you can do it in different way as below
1.let document loading complete and record if you need to redirect the page while rendering
2. add a unique request-id identifier for each page load
3. invoke ajax call with request-id ( may be rest call) to server asking if page needs to be redirected.
4. if page needs to be redirected , do so, via javascript in browser at client end.
A HTTP response consists of headers and an optional response content.
Once you have started to write the response to the socket connection you can't revert it. In your example: If you run into an error in the middle of content generation you can't add a redirect header - the header section has already be written.
The statement above is not entirely true: in HTTP chunked transfer encoding the response is sent in separate chunks. The last chunk can have an optional trailer containing entity-header fields and theoretically a redirect header. But if you can use these mechanism is a different question. For instance a servlet container may use chunked transfer encoding but does not give you an API to set the trailer.
But writing must not start immediately: For instance HttpServletResponse maintains a buffer for the response content. If you set headers and start writing the content only the buffer is filled and you still can reset the response and start all over. But once the buffer overflows the response is written to the connection and the HttpServletResponse is now committed.
Such a mechanism gives you way to deal with errors during content generation which happen when the response is not yet committed: Just reset the response and send an error message instead. You could examine your framework if it supports such an mechanism. But obviously this is not a solution for larger responses.
A second way to avoid errors during content generation is simply to make sure that they can't happen. First gather all your data needed for the response (e.g. making unsafe database calls), then in a second step generate the response - the second now step should not fail (except if you have bugs in your code).
You already mentioned a third way to handle an error, by having the client sanitize the response and take some action it errors are detected (e.g. by including a script in the generated HTML response).
The only reliable way to do this is to create a proxy HttpServletResponse object that caches the response. You'd need to give the uPortal this proxy instead of the actual HttpServletResponse, and only send the output using the real response once the processing completes / send redirect if the processing fails.
It is HTTP protocol design limitation that you cannot send HTTP redirect once output was started.
Other possible ways rely on HTML or Javascript redirects, but since you write that the error may happen at any moment, it would be difficult to print it out in a way that the browsers would reliably interpret it as redirect.
Basically I need to provide REST service that would receive a String param, use that param to fetch a file from another system and then return the fetched file back as the response.
The effect should be the same as when a user clicks on a pdf or any other binary file link and the browser prompts him to save/download that file.
A couple of points:
is it possible to stream the file (to send bytes as I receive them from source system). In other words, how to handle very large files?
also related to streaming, when using regular HttpServletResponse, do I have to wait until a large file is completely read to return response.build()?
How do I go around doing this using Apache Wink?
PS Sorry, this may be trivial for Wink gurus, but I'm just starting to wrap my head around developer guide.
You can just return the java.io.File from your method. You can wrap it with Response if you like. Wink will handle the streaming. The streaming doesn't start when you call to response.build(), but rather when your method finishes.
If you want a correct download dialog, you should return the proper Content-Disposition header. See How to set response header in JAX-RS so that user sees download popup for Excel?
Well, I'm Trying to Make a Data Importing Module. From the module, the user choose the .txt File with Data and then click the upload button. I want to make a Textarea or textbox (My project is a Java EE WebApp) where the webapp shows the real-progress of the upload proccess with Descriptive Messages.
I'm thinking (And i've searched) about Multiple Ajax Requests, and, Multiple Ajax Responses with one Request (The last one is not valid, as i read), but, i'm confused about the usage of AJAX in this case. It is Valid the user hit "Upload", and then, i call an AJAX Request that returns the text with the progress of the actual registry imported?
I'm thinking to use:
jQuery 1.6.2
GSon (For ajax)
Any suggestion would be appreciated
I would recommend using JBoss RichFaces 'poll' mechanism for that, or just a simple jquery script on the client side:
Ajax Poll Example with RichFaces: http://richfaces-showcase.appspot.com/richfaces/component-sample.jsf?demo=poll&skin=blueSky
JQuery (loads of examples on the web):
http://net.tutsplus.com/tutorials/javascript-ajax/creating-a-dynamic-poll-with-jquery-and-php/
jQuery AJAX polling for JSON response, handling based on AJAX result or JSON content
How about using a iframe that handles the upload form? This way it would not require the browser to update (by AJAX calls) the contents of a page that "we're already leaving". The iframe could be styled so that it's indistinguisable from other content.
AJAX-calls to a some method that keeps an eye on to some progress-variable (lets say a double that indicates percentage) is perfectly valid. Below is a barebones pseudo-example.
!PSEUDO!
double progress = 0.0d
void upload(request, response) {
// updates progress real-time
}
void ajaxProgress(request, response) {
// set progress to response
}
You may want to consider all the traffic back and forth showing real time processing information of uploaded files.
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();
}
My goal is to redirect or refresh my page while downloding excel file :
Details :
In my application i am sending dynamically generated excel file
setContentType("application/vnd.ms-excel; charset=windows-1254");
setCharacterEncoding(Constants.ENCODING);
setHeader("content-disposition", "attachment;filename=" + Constants.DEFAULT_EXCEL_FILE);
setHeader("Location","http://www.google.com");
But after asking user to save or open excel file, it didn't redirect to ex : google.com.
Is it possible to do it in header part ? If yes please say how .
Thanks.
This is simply isn't possible for the reason that the defined behavior of the browser is bound to be vague. In other words, when the browser notes the presence of two headers, each with possibly conflicting requirements, then the behavior might be to simply ignore one, instead of obeying both - it is upto the browser vendor to define this.
In this particular case, the Content-Disposition and the Location HTTP headers are conflicting, more so because if the browser were to process the Location header first resulting in the redirection, the end-user would never be prompted for the file download.
On an additional note, the Location header would only make sense for a HTTP 302 response (I believe that this is not the case in your application, not that it might help).
You could use some JavaScript for the job
<a href="myfile.txt" onclick='window.location = 'http://www.google.com/';">
File
</a>
you cannot redirect,because you have flushed out the response stream.
This is one option, not in header part tough
private void DownloadFile()
{
//Download file here...
//Refresh this page.
this.Response.Redirect(Request.Url.AbsolutePath);
}