I have a web page that has a function that will send an initial request to a web service.
After some predefined time, the user can send a second request.
After the user sends the first request, I want the web page to countdown when the user may send the second request.
After the countdown, I want a DB field to be updated automatically, indicating that the appropriate time has passed.
When the time has passed and the DB updated, I'd like the webpage updated to show a button that would allow the user to send the second request.
After the initial request, call a JavaScript user-defined function "countdown()" using the in-built JavaScript function "setTimeout("countdown()", 4000)", where the number "4000" resembles the number of micro-seconds that need to be passed to fire the function mentioned in the first parameter.
In the "countdown()" function, write the logic for the AJAX call, where you will be updating the database that the desired time of 4 seconds (for example) has passed & now the user can send the second request.
Also in the same AJAX call, you can print out some word (let the word be "yes" for example), which you can catch / fetch it in the "countdown()" function definition, using the "responseText" keyword of JavaScript's "XMLHttpRequestObject", in a dummy variable "flag".
Now you can write something like the following in the "countdown()" function definition:-
function countdown() {
document.getElementById("btn_second_req").style.display = 'none';
var flag = '';
// all code to prepare for AJAX call
// AJAX called, return also fetched in a variable "flag".
if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) {
flag = XMLHttpRequestObject.responseText;
}
if (flag == 'yes') {
document.getElementById("btn_second_req").style.display = 'block';
}
}
So by default, the second request firing HTML button is hidden from the very first time, & only activated when the "flag" variable condition is satisfied.
Also since the details of the first call of any user is being kept in the DB, so in the second call, you need to check with server validation that there exists details for the first call, otherwise the second request call will not be entertained.
These type of logic can easily be implemented using any JavaScript framework library (like jQuery or Prototype) or by plain JavaScript only.
Hope it helps.
Yes, it can be done. Here is how I would do it, which is almost as you describe it.
1- The web page sent the request to the service. The service compute the time until the next request can be executed, store it in a db field/in session (depending how your service work), and send it back to the client, plus whatever it is your service send back.
2- You create a timer with the setTimeout function of javascript (or an equivalent if you use a javascript library) http://www.w3schools.com/js/js_timing.asp .
3- When the timer execute, you send a request to the webservice to ask if its ok to start the second request. The server check the time in the db field. If it is past "next request time", the server respond positive, else it return the remaining time, and the client then create a new timer.
4- You send your new request. The server check again if its "next request time" (in case someone smart hack the javascript, or if their is a bug on the client). If it is time, it execute the second request.
The only difference is that with the way I described, everything on the server execute as the result of a client action, so you don't have to mess with thread/cron job to auto update your db field.
Good luck!
Related
I'm working on a web app, which is communicating with the server with AJAX requests. A special type of "close" request takes 5 secs, which the web app should just fire-and-forget, the result is irrelevant. Due to browser behaviors (only limited number of simultaneous AJAX requests are performed), a 5-sec request may stuck other AJAX requests, which is unacceptable.
The smart folks here in StackOverflow has adviced me to write a small server-side proxy, which the web app should call instead of the original 5-sec one. The proxy should response immediatelly, close response channel, then perform a HTTP request and wait for it, spending the 5 secs server-side, instead of client-side. (The original question is here: See Is there a way to perform fire-and-forget AJAX request? )
The server is a Tomcat with JSP, and I can write small JPS pages. (I'm not an experienced JSP ninja, but I don't afraid of Java.) My question is: is it legal to write such a JSP, or what's the best practice:
send the response,
close reply channel (is out.close() enough?), in order to end the AJAX request at client-side,
fire and process (actually: just drop response) a HTTP request "in background", which may take as long as 5 secs?
It's not (only) your browser you should worry about. Blocking a tomcat thread for 5s severly limits your max-users as well (how many requests per second do you need to handle ultimately?)
So making it "more" asynchronous in the server might make sense.
Doing it in JSP (with Sriplets?!) alone will noway be a robust implementation - but if you need to do it that way, you should think about starting the "work to do" in a separate Thread.
So instead of
<%
do_something_heavy();
%>
You'll do like
<%
new Thread(new Runnable() {
public void run() {
do_something_heavy();
}
}).start();
%>
There's other options as well (JMS, ExecutorService, Spring #Async...) but this should get you started quick.
First the best is to separate business logic from view: it means write java code on a servlet and delegate only the view aspect to the jsp.
To execute your task asynchronously in the servlet code you can:
Invoke a submit method of an ExecutorService
Make a call to a JMS
Manually create a thread and start it
Then you can forward to the jsp.
TIP: It is possible to assign an id to the long task and return it in the jsp with a link to monitor the status of the task.
Basically you do something like that:
Accept the request
Start asynchronously a thread to execute the long task
Return immediately without waiting for the long task termination
Or using an id:
Accept the request
Calculate the id of the task
Start asynchronously a thread to execute the long task with the desired id
Return immediately a link with the id of the long task without waiting for the termination
Recently I am working on a project which using ajax to call java servlet, and the request takes more than 10 sec to get the response, so I need to make sure during this time user won't be able to submit the form again, and my current approach is detect submit button click event and disable submit button, once success or error function is triggered in ajax, enable the button again, but this is not a good approach.
---- Edit ----
Sorry, I wasn't explain clearly, what I mean is this can stop non technical background user, but if any one intend to attack the site or whatever reason,
they can simply modify html code to enable the button, and do another submit,
Before I tried another way which set a cookie interval after form submit, and check the cookie when request finish, but just wondering whether there is any other way to do this, this question is purely for learning purpose.
Sorry for my English:)
I dont see anything wrong with disabling the button, that is what I frequently use, because this not only provides an indication that the system acknowledged your click but also prevent the user from clicking again.
If for some reason you dont like that you can disable the underlying method call something like this:
var isSubmitting = false;
function handleClick(){
if (!isSubmitting)
{
isSubmitting = true;
$.ajax(
"http://yourservice/submit" {
data: {someData:123},
contentType: 'application/json',
type: 'POST',
success: function(){
isSubmitting = false;
},
});
}
}
About your edit, the cookie sounds like a good approach, basically you need something that the server is going to pass to the client, and then check on submit. once that has been authorized the server will prevent processing of further requests with the same parameter.
But bear in mind that a malicious user would spawn thousands of requests to get cookies and then perform all the submissions anyway, so it is not really a defence against attackers, for that you would have to implement some form of throttling.
So in the end if you just want to prevent accidental submissions the button hide will suffice.
Something I have done and has been successful is a combination of what you described and preventing the function called by the button to execute twice. I do this by keeping a variable that gets set to true with the first request, then on subsequent request I check for it, if it's true, I don't do anything. Something like this:
var isRequestAlive = false;
var submit = function(){
if(!isRequestAlive){
isRequestAlive = true;
doAjaxStuff("", function(){
isRequestAlive = false;
})
}
}
I have a form that creates an account and a servlet that handles the request.
However, the process to create this account is a long process and I want to create something like a status bar or a progress bar. Heres the POST:
$.post("createAccount.jsp", function(data) { $("#status").text(data);
});
And the servlet would continuously print data like "creating x..." then "creating y" as the servlet runs. Is there a way to accomplish this or maybe another way to tackle this issue?
Thanks
Http works on a request-response model. You send a request, and server responds back. After that Server doesn't know who are you?!
It's like Server is a post-office that doesn't know your address. You
go to it and get your letters.It doesn't come to your home for
delivering letters.
If you want constant notifications from server, You can either use Web Sockets(Stack Overflow also uses Web Sockets) or use `AJAX Polling' mechanisms,
which sends an AJAX request to the server and waits for server to
respond. On retrieval of response,it generates another AJAX request
and keep on doing the same until server stops generating new data.
Read this for an explanation of AJAX Polling techniques
You could have your account creation servlet update a database or context attribute as it creates the account.
You could have a separate AJAX request to a different servlet that sends back to the webpage the most recent development found in the database or context attribute. You would then poll your server with that AJAX request every so many fractions of a second(or relevant time interval depending on how long of a task it is to create an account) to get all the updates.
What I want is to get database updates.
i.e If any changes occur to the database or a new record is inserted it should notify to the user.
Up to know what I implemented is using jQuery as shown below
$(document).ready(function() {
var updateInterval = setInterval(function() {
$('#chat').load('Db.jsp?elect=<%=emesg%>');
},1000);
});
It worked fine for me, but my teacher told to me that it's not a good way to do recommended using comet or long polling technology.
Can anyone give me examples for getting database updates using comet or long polling
in servlets/jsp? I'm using Tomcat as server.
Just taking a shot in the dark since I don't know your exact environment... You could have the database trigger fire a call to a servlet each time a row is committed which would then run some code that looked like the following:
Get the script sessions that are active for the page that we want to update. This eliminates the need to check every reverse ajax script session that is running on the site. Once we have the script sessions we can use the second code block to take some data and update a table on the client side. All that the second code section does is send javascript to the client to be executed via the reverse ajax connection that is open.
String page = ServerContextFactory.get().getContextPath() + "/reverseajax/clock.html";
Browser.withPage(page, new Runnable() {
public void run() {
Util.setValue("clockDisplay", output);
}
});
// Creates a new Person bean.
Person person = new Person(true);
// Creates a multi-dimensional array, containing a row and the rows column data.
String[][] data = {
{person.getId(), person.getName(), person.getAddress(), person.getAge()+"", person.isSuperhero()+""}
};
// Call DWR's util which adds rows into a table. peopleTable is the id of the tbody and
// data conta
ins the row/column data.
Util.addRows("peopleTable", data);
Note that both of the above sections of code are pulled straight from the documentation examples # http://directwebremoting.org/dwr-demo/. These are only simple examples of how reverse ajax can sent data to the client, but your exact situation seems to be more dependent on how you receive the notification than how you update the client screen.
Without some type of database notification to the java code I think you will have to poll the system at set intervals. You could make the system a little more efficient even when polling by verifying that there are reverse ajax script sessions active for the page before polling the database for info.
I had the following:
Link 1
but I noticed that the javascript function CreatePageView() did not get executed all the time and was creating a race situation. Sometimes the javascript would get executed, others times the redirect was happening first.
So I wanted to control the order of events and thought to invoke the servlet within my javascript function.
function CreatePageView()
{
//Execute javascript function here
//Invoke servlet here
document.forms[0].action = "/servlet/MyServlet";
document.forms[0].submit();
}
When I invoke my servlet, my session gets destroyed and I get redirected to the login page. Can anyone explain why this is happening? Or perhaps suggest an alternate method of invoking the servlet without killing the session? Thanks in advance.
This sounds much like as if that JavaScript is firing an asynchronous request. Otherwise the problem doesn't make any sense. The link's action will in any way only be executed when the JavaScript function has returned. But when you're firing an asynchronous/ajaxical request in the JS function, then indeed a race condition may occur. It namely doesn't execute in sync. It executes "in the background".
You need to ensure that the link is only invoked when the asynchronous request is finished. Assuming that you're doing it in "plain vanilla" JS by XMLHttpRequest instead of a convenient Ajaxical JS library like jQuery, then you need to do the job in the onreadystatechange.
Change the link as follows:
<a href="/servlets/MyServlet" onclick="return createPageView(this)">
(note that the javascript: pseudoprotocol is unnecessary and that JS functions usually start with lowercase)
And fix your JS function as follows (not MSIE compatible, fix that yourself)
function createPageView(link) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
window.location = link.href; // See?
}
}
xhr.open('GET', 'http://example.com', true);
xhr.send(null);
return false; // Block link's default action.
}
As to the question why the session get destroyed, it will be "destroyed" when the request headers doesn't contain the proper session cookie, or when you call session.invalidate() in server side, or when the request is been fired on a different domain/context. You're the only one who can investigate which one is the culprit.