let's say I have this code in javascript:
function doAnAjaxCall () {
var xhr1 = new XMLHttpRequest();
xhr1.open('GET', '/mylink', true);
xhr1.onreadystatechange = function() {
if (this.readyState == 4 && this.status==200) {
alert("Hey! I got a response!");
}
};
xhr1.send(null);
}
and let the code in the servlet be:
public class RootServlet extends HttpServlet {
public void doGet (HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.getWriter().write("What's up doc?");
resp.setStatus(200);
}
}
Will xhr1 still wait for new changes in readystate? Or it is closed as soon as it gets the first response?
If it remains open, will it lead to memory leaks/slower browser after a while and accumulating a few of those?
Should I always call resp.getWriter().close() at the end of the servlet code?
And, lastly, for the jQuery fans out there:
does $.ajax() behave as XMLHttpRequest() in that respect?
Will xhr1 still wait for new changes in readystate? Or it is closed as soon as it gets the first response? If it remains open, will it lead to memory leaks/slower browser after a while and accumulating a few of those?
Behind the scenes, it remains open. It (and the memory occupation) is however the responsibility of the webbrowser engine. It maintains a certain amount of connections in a pool which has a maximum limit per domain anyway. MSIE for example has a bug which causes them to leak away when they are still running while the user unloads (closes) the window.
Should I always call resp.getWriter().close() at the end of the servlet code?
Not necessary. The servletcontainer will close it anyway. Closing it yourself only prevents the risk of some (buggy) code further in the response chain from writing to the response body. For more detail, see this answer.
And, lastly, for the jQuery fans out there: does $.ajax() behave as XMLHttpRequest() in that respect?
It uses XMLHttpRequest under the covers (only when supported by the browser; otherwise it's the MSIE ActiveX object). It constructs a new one on every call. Open the unminified source code, Ctrl+F the jQuery.ajaxTransport( function. All the ajax handling code is almost 200 loc and it covers all possible browser specific bug fixes you can think about.
Related
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;
})
}
}
Obviously, the doGet method has a return type of void, so, it doesn't return anything. In this sense, I'm using the word "return" to mean send the response back to the client that requested it.
I'm trying to implement a long-polling Servlet. It would be beneficial for it not to send a response until I have something that I would like to send back. So, in the doGet method I add the connected user's ID and AsyncContext to a map:
private ConcurrentMap<String, AsyncContext> contexts = new ConcurrentHashMap<>();
//...in the doGet method when I need to add the context...
contexts.put(userId, context);
Then, when I have something to send back, I can retrieve the appropriate context and write to it's responses output stream:
AsyncContext context = contexts.get(userId);
PrintWriter writer = context.getResponse().getWriter();
writer.write("something to send to the client");
But, the client never seems to receive the response. Looking at the Network tab in the developer console of the browser, I can see the GET request is sent and then returns (with a status of 200). This occurs before I actually send something back. Which is leading me to believe that after the doGet method is finished the response is returned. And perhaps because of this, after this point, nothing can be sent to the client because the connection is not opened.
Does the doGet method send the response to the client once the method is finished executing? If this is the case, how can I keep the connection open for a long-polling effect?
To answer my own questions: Does the doGet method send the response to the client once the method is finished executing?
Yes, when the doGet (or any HttpServlet method, ex: doGet, doPost, etc.) method finishes executing it sends the response back to the client.
If this is the case, how can I keep the connection open for a long-polling effect?
Using asynchronous Servlets (which I was using, however, I found my particular problem must be elsewhere, yet these answers are still relevant to the questions asked). On the ServletRequest object call the startAsync method, like so:
AsyncContext context = request.startAsync(request, response);
"This will notify the Web Container that at the end of the request call it should free the handling thread and leave the connection open so that other thread writes the response and end the connection."Reference Link.
Also, I will add the solution to my particular problem (the client wasn't receiving the response) was because in my Servlet, I wasn't calling the complete method on the AsyncContext object:
asyncContext.complete();
Yes, the response stream is flushed and closed when doGet() finishes executing.
Keeping UI threads occupied for extended periods of time violates Java Enterprise best practice.
Recommend you rather return immediately if nothing to respond, and implement a timer on the client (browser) side to poll the server for results every so often.
I have the following lines of code that gathers the source code from a given URL:
URL url = new URL(websiteAddress);
URLConnection connection = url.openConnection(); // throws an IOException
connection.setConnectTimeout(timeoutInMilliseconds);
bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null) {
outputString += line;
}
However, the problem that I'm having is that wi-fi hotspots often redirect you to a page where you have to click "I Agree." If you run this code before you have clicked that checkbox, then it gathers the source code from the hotspot login page, rather than the intended page.
What I want to do is have some way of checking whether or not the intended page was reached. I was hoping that calling connection.getURL() after creating the InputStreamReader would show me the actual web page that was arrived, but no such luck. How can I determine whether or not the intended URL has been redirected?
One way would be to look for any specific element in your web page, and if its not there then you know that you may be in some other page (possibly redirected to some login page).
The only thing I can suggest is to have a server where you know what the response is, and query that first to ensure connectivity to at least that server. That will (typically) be enough to assume full connectivity.
You can then go on to query the url you're interested in.
The challenege is that if a computer asks for the page at some url, the way a lot of wifi hotspots work is to intercept that request and return the page. There's often no clue, form the computer's POV that the page returned is not the page requested.
One option would be to call setFollowRedirects(false). By default, a connection will quietly follow redirects and try to reach a page which returns a 200 HTTP response. Disabling redirect following will make confirming the expected page is returned easier, simply confirm the response is a 200.
That said, #rec's comment is worth taking into account - it isn't enough to simply check the response code, because there are many different ways a router could interrupt your request, many of which are not detectable. A malicious router could, for instance, intercept all your requests and change the responding content in a subtle but dangerous way - this is called a man-in-the-middle attack.
By definition you cannot avoid MitM attacks unless you can open a secure and trusted connection (generally, HTTPS) between yourself and the remote site, however assuming you aren't really concerned about attacks, the better tactic is simply to assume the data you get back could be broken in any number of ways, and instead make your scraping logic more robust to that possibility.
I can't speak directly to how you would make your logic more robust without understanding your use case and the issues you've run into, however the gist would be to add checks where issues might arise, and throw an exception that you then handle gracefully higher up the stack.
For instance, if your code was:
System.out.println(outputString.subString(outputString.indexOf('A'));
This would fail if outputString didn't actually have an'A'` character. So check that explicitly:
int aPos = outputString.indexOf('A');
if (aPos < 0) {
throw new InvalidParseException("Didn't find an 'A', cannot proceed");
}
System.out.println(outputString.subString(aPos);
And handle the InvalidParseException wherever makes the most sense for your use case.
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.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Should one call .close() on HttpServletResponse.getOutputStream()/.getWriter()?
Am I responsible for closing the HttpServletResponse.getOutputStream() (or the getWriter() or even the inputstream)
or should I leave it to the container ?
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
OutputStream o = response.getOutputStream();
...
o.close(); //yes/no ?
}
You indeed don't need to do so.
Thumb rule: if you didn't create/open it yourself using new SomeOutputStream(), then you don't need to close it yourself. If it was for example a new FileOutputStream("c:/foo.txt"), then you obviously need to close it yourself.
Reasons that some people still do it are just to ensure that nothing more will be written to the response body. If it would ever happen, then this will cause an IllegalStateException in the appserver logs, but this wouldn't affect the client, so the client still gets the proper response. This is also an easier debug to spot the potential problems in the request-response chain which you wouldn't see at first glance. For example, something else is appending more data to the response body somewhere further down in the chain.
Another reason which you see among starters is that they just wanted to prevent that more data is written to the response body. You see this often when JSP incorrectly plays a role in the response. They just ignore the IllegalStateExceptions in the logs. Needless to say that this particular purpose is bad.
No you don't need to close it. If you do you basically end the response to the client. After closing the stream you cannot send anything else to the client until the next request. You didn't open the stream, so you don't have to close it.