I understand that this question is asked over and over again, but I want a way to handle back button clicks on the server side (like banking applications).
When the user clicks on the back button, the page should be invalid and the user should be asked to start all over again.
Can you direct me to some tutorials on this?
The simplest way I've seen this solved is as follows.
Every page is served up with a unique ID/token.
That unique ID is always submitted when submitting any forms, and tracked on the server as being "used".
If the user ever clicks "back" and re-submits the same form, the server checks the unique ID... notices that it is a duplicate and then ignores the submission.
Note this won't physically stop a user from going "back", but if the last action was "transfer $1,000,000 dollars!" - the user won't accidentally transmit 2 million.
Make pages not cachable
track the user route server side, if she is visiting the visited page which she isn't supposed to revisit by back, in a session data may be.
check to see if she is requesting the visited resource then handle accordingly
Filter is the best place to do
Instruct page to use no cache.
Add to the head element of the page
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
There are two problems you need to solve here.
The first is how browsers typically handle the back button. You should use a POST request to get to the page that the back button should not have access to. Most browsers will use a local cache for GET requests,, so if you do a GET, your server simply won't be accessed at all. A POST request will however typically perform a new request. Many browsers will also warn the user, and show a dialog box saying i.e. "Are you sure you want to send the form again?". So by using a POST, you increase the likelihood that every page load of that page will perform a new request to your server.
You may also be able to use a GET request where your server returns HTTP headers that makes browsers not load the page from the cache. Experiment with this.
The second problem is to make sure you invalidate duplicate requests server side. The first solution I can think of is to generate a token that you submit with the form and store in a database on every request. If a request is performed with a token that already is stored, you can invalidate the request. Perhaps there are better techniques, but I'll leave that as an exercise for the reader ;)
I also searched for this , and after all i found a little trick i think it may for your.
Every page your have an javaScript function that call to server with
ajax to check whether this page is available at that time.
In the server side you keep the availability (with the session).
If not redirect the page as you wish .
Related
First Question:
Consider, I am filling any form then I refresh that page,what I want is what ever I fill in that page should not clear not only refresh page even if network problem occurred during filling the form.
Second Question:
If I login with any username and password then I fill in form and if network problem occurrs during filling the form then I go to another machine and login with same username password, I want whatever I entered In previous system should be show in this machine.
Sorry for my poor english, please tell any idea.
You should try and leverage client side storage. This will allow you to store the user data on the local browser. Here is an article on this http://www.html5rocks.com/en/tutorials/offline/storage/
I hope it helps
Fixing the following requires:
1 - Background worker on the client side that posts the data to the server .
Worker;
//or
window.setInterval();
2 - A banner or a status div showing the user that he is connected or disconnected.
var isOnline = window.navigator.onLine;
3 - Notify the user about reloading the page.
window.addEventListener("beforeunload", function (e) { alert('Your leaving...') });
Your first question has a pretty simple and straightforward solution: you'd want to save the data on the local machine, using something like cookies or localStorage.
For your second question, you'd need a much more complicated solution. Basically, you need to constantly persist the view data (input values, etc.) to the server for "safekeeping", since you assume the machine might crash at any given moment.
So your backend should support saving "temp form data", and whenever a user enters the relevant screen, you need to check for such temp form data on the backend, and populate the form accordingly. This will probably cause lots of edge cases and isn't trivial IMO.
I got a problem regarding request.getParameterMap()
In my jspx file multiply parameters are added when the user selects items out
of a table. now that i want to get them in my Controller
with request.getParameterMap(); it doesnt work with Firefox, Safari
but it works fine with chrome
anyone has an idea why it is so ?
thx for the replies .. the html form with the request parameters is build dynamicly at runtime using javascript, which seems to cause problems with widged based browsers like safari, firefox and most likely IE.
i will use ajax to get it work
The problem is not in the way that you are getting the parameter values from the map. It cannot be. The problem has to be in the HTML / Javascript / whatever that is creating the request on the client (browser) side.
It is most likely that you are doing something that is not strictly HTML (or whatever) compliant. Some browsers are treating it one way, and others another way. I suggest that you start by running an HTML validator over the page.
browser is not aware of request.getParameterMap() or any method in servlet api.
In your use case : you have a table of data , out of which user may select some rows and you need this data in server side for some action on those rows.
For eg : mark as read in GMAIL
select one or more rows in gmail and click ,mark as read will sent some request to google server and get those rows marked as read by user.
You can do it this way, you need to send primary key of your rows to server side with same parameter name
for eg: /delete?delId=1&delId=3&delId=7
and use request.getParameterValues() in server side to retrieve a list of ids to be deleted.
I have one "user search" portlet on the home page of one application running on websphere portal server which displays the matching user records as per the search criteria filled in the search form. I have a requirement to have a "back to search input" link on the results page which on click should show the filled form on the input jsp.
The issue I am facing is if I open the application in two different tabs of same IE browser and start giving some search criteria and submit and at same time search for some other input from the other IE tab (in the same browser) and then go back to previous tab and click on "back to search input" link, instead of showing me the first input it will show me the input I entered in the next IE tab.
I am setting and getting the bean (form bean) through portlet session. But in the two diff tabs of the same IE it will be the same user session (and may be the same portlet session.)
How can I fix it so the two tabs save their search results independently?
The one thing to note here is I can access this "user search" application without logging in. So it must be taking the default portlet session in this case. What will happen once I login and then search; will it overwrite the portlet session and http session?
Basically your issue stems from the fact that your session is the same in both tabs so any data you store you can't expect to be different between tabs unless you store it as such. I would assign each search an id and store them in a collection in your session. Then when you draw your "back to search input" button add the search id such that you can pull the correct search out when building the input page.
Alternatively you could save server memory by posting the search as a query string on the return to search link rather than storing it in session.
What you describe is a fairly common problem faced by web app -- I think the official term is conversations -- which is the need to support something in-between the session scope and the request scope.
Some web framework support this concept, some not. The portlet specification does not support that out-of-the-box (Maybe there's something specific in websphere though).
I think one way to re-create the support for conversations, is to store a conversation id in the HTML generated. This way you can have an ID that is be per-tab / window. If suddenly a request receive an old ID, you know it comes from either an old page (if the user used the back button), or another tab.
That's ony a rough sketch. I'm pretty sure there a good resources on the web about this problem, otherwise spawn another question.
I write, because I can not solve the following problem.
I have a servlet that processes some information.
In response I put both text and binary content.
How do I get two response, then two html page, starting from the same request?
is a thing possible?
The first response should continue to do what he does now, while the second would appear to make a popup window to save an image.
There are easier ways to achieve the same result?
Many thanks in advance
As answered in your previous question, You can send only one HTTP response per HTTP request. This is not a servlet restriction, this is a HTTP restriction. The server is not supposed to send data to the client unaskingly. That would have made the Internet extremely annoying and unusable. As if you're thrown dead with a continuous stream of spam.
To be able to return two responses, the client has to fire two requests itself. If you want to do this automagically on a "single click", then you can (ab)use some shot of JavaScript for this. E.g.
click
This will fire two requests, one to page.jsp using normal HTML in current window and another one to downloadservlet/file.ext in new window using JavaScript. This window will however disappear if the response is of Content-Disposition: attachment as answered in your previous question.
You only need to take into account that this won't work when the client has JavaScript disabled.
Say, you are submitting a form, which affects your database (adding records/ deleting them/ updating them) and this is how your request looks like:
POST /application/action=update
Now, say, you are done with your update, so you would like to take the user to the home page.
Response.sendRedirect /application/action=home
This works wonderfully well. User is sent a redirect after POST, so even if the user tries to refresh the page by hitting F5, you are good. However, this will not work if you did this:
requestDispatcher.forward(/application/action=home)
Given that there is a scenario where you have to display different kinds of error / success messages after you are done with your update, you are most likely doing a forward after POST. In such a scenario, how do you avoid update actions from happening twice?
I find it rather amusing that many secure sites (banks) / payment gateways tend to inform the user by placing text on screen, such as "Please don't press back / refresh buttons".
Is there no better way to handling this? Other than requesting the user not to press these buttons? When I last checked, there was something called the 'Vertical Response Cache'. A Filter that would identify uniqueness of your request in a session and tries to send a cached response if the request is duplicate. Are there any simpler ways to solving this classic problem?
Here is a link to the vertical response cache solution I was talking about: http://www.fingo.info/en/articles/_1.html. I am, However, not sure as to how well this really works.
Yes, I believe that you should redirect after a POST, with the exception of API requests. Without doing this not only do you have to worry about getting duplicate POSTs when the user uses the back button, but the browser will also give the user annoying dialogs when they try to use the back button.
Response.sendRedirect works in practice, but tecnically speaking this is sending the wrong HTTP response code for this purpose. sendRedirect sends a 302, but the correct code to use to transform a POST into a GET is 303. (most browsers will treat a 302 just like a 303 if they get it in response to a POST, however)
In general you want the redirect to send the user to whatever view will display the effect of their change. For example, if they edit a widget, they should be redirected to the view of that widget. If they delete a widget, they should be redirected to the view that the widget would have appeared in when it existed (perhaps the widget list).
Sometimes it's nice to have a status message to further drive home the fact that an action occurred. A simple way to do this is to have a common parameter to your views that, when set, will display an action completed message. eg:
/widget?id=12345&msg=Widget+modified.
Here the "msg" parameter contains the message "Widget modified". The one downside to this approach is that it may be possible for malicious sites to give your users confusing/misleading messages. eg:
/account?msg=Foo+Corp.+hates+you.
If you're really worried about this you could include an expiring signature for the message as an additional parameter. If the signature is invalid or has expired, simply don't display the message.
The best solution to solve the problem of showing status messages to the users after a POST to GET redirect is to use user sessions.
How
Add attributes to user session with value as set of messages to be displayed. for eg.
userSession.put("success_messages", new HashSet<String>(){"Success", "Check your account balance"});
userSession.put("warning_messages", new HashSet<String>(){"Your account balance is low. Recharge immediately"});
And have a filter which scans the user session for these particular attributes and outputs the messages. The filter should delete the attributes after reading once, as the status messages are generally displayed only once.
One thought that I've had is to embed a unique ID (probably a random string) as a hidden form field in the form that is being POST-submitted. The ID string can be put in the database as a "transaction ID". Now, when you go to update the database, first check whether there's an existing record with the submitted transaction ID, and if so, assume it's a duplicate and don't change the database.
Of course, as I said, this is just a thought. I don't know what methods are actually used in practice. (I suspect that a lot of less-critical sites just ignore the problem and hope their users will be smart... a losing proposition if I ever saw one ;-)
EDIT: as pointed out in the comments, storing transaction IDs in the database might take up a lot of space, but if that's an issue, you could keep an in-memory cache of all transaction IDs processed in the last 5 minutes/1 hour/1 day/whatever. That should work unless you're up against a determined hacker...
I find it rather amusing that many secure sites (banks) / payment gateways tend to inform the user by placing text on screen, such as "Please don't press back / refresh buttons".
some people find its better to "disable all Back, Refresh event on this critical pages";
I'm not sure if this is good or not.
But your addressed solution "vertical response cache" sounds nice
Its a little non-obvious but:
create a keyed-object in the user session.
the value is a Request + java Future for the result
return immediately with a client-side redirect.
while the client-side redirect is being handled, have a worker thread work on producing the answer.
So by the time the client browser completes the redirect, getting the new page's images, etc... the results are waiting for the user.
The alternative is to make the user painfully aware of how long the database is taking.
Security Update (2011 Jan 24 ) :
The key is vulnerable to attack since it is part of the response to the client, so
Generate a random key
Use user's session id as a salt to create a SHA-1
Store both the random key and the SHA-1 in the database with (, ) as the primary key. (no separate indexing on the RANDOMKEY.
Use both RANDOMKEY and the SHA-1 as the db lookup.
Do not store the Session Id (avoid privacy issues with being able to corollate many entries to the same user)
Expire the results after 2-3 days. ( Allows a daily batch job to do the clean up and avoids creating problems for user sessions that are semi-long lasting )
This method requires any hacker to know both the session id and the random key.
This approach may seem overkill, but a redirect-hardened mechanism can be used for situations like password resets.
If you are working with java server side scripting and also using struts 2 then you refer this link which talks about on using token .
http://www.xinotes.org/notes/note/369/
A token should be generated and kept in session for the initial page render, when the request is submitted along with the token for the first time , in struts action run a thread with thread name as the token id and run the logic whatever the client has requested for , when client submit again the same request, check whether the thread is still running(thread.getcurrentthread().interrupted) if still running then send a client redirect 503.
Please look at the ExecuteAndWaitInterceptor of struts 2code, the logic of this combined with token will help out fast click