Servlet redirect doesn't display requested page - java

I have a page - lets call it page X - where I do an ajax call that populates my table constructed with jqGrid. So here I call localhost:8080/servlet/ajax/Data.json which is a servlet.
Now, if the page expires and the user still wants to access the table (search data for instance) I would like to redirect the request to the Login page.
The ajax call calls the Data.json servlet that is not in the same servletcontext as my Login page (which is localhost:8080/servlet/myapp), therefore I cannot use servlet forward (I am using JBoss 4.2 and I can only forward in the same servletcontext).
I have tried to redirect with sendRedirect, which is able to call the Login page that is actually executed but not displayed. And this is where I got lost. My Login page is executed and I still see page X.
I have tried to write the returned HTML (from Login page) into the response of page X (I also set the Content-Type to text/html). The HTML is returned in the response, but not displayed.
I am using Apache Turbine which is another servlet that retrieves a page when requested.
Do you have any ideas? I don't know what to do.

It looks like your servlet at servlet/ajax/Data.json is telling the AJAX request to redirect to the login page. Then the page is going to try to render the jqGrid table with the login page, which probably won't work.
You need to add code where you are making the AJAX call to servlet/ajax/Data.json to check to see whether the browser itself needs to be redirected. Either if the servlet returns a 302 redirect as a response, or if the servlet returns an error that's simply "SESSION EXPIRED", so the javascript on the browser's end that's making the AJAX call to the servlet knows the session has expired and to redirect the browser to the login page.

Ajax calls are asynchronous calls, sendRedirect call on ajax calls never be effective (ajax response always sends response to initiator).
You may need to use XMLHttpRequest status code to find out the page expiration and then use java script window.location to reset the browser url to login url.

Related

How to redirect Ajax request to Login Page in Java

I want to redirect an Ajax request to login page at server side.
I can understand whether request is an Ajax request or not with
boolean isAjaxRequest = "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
I know I can do it in JavaScript but there are a lot of places sending ajax request to server. So I have to do it in server-side. I tried;
httpResponse.redirect("...");
but it does not work.
How can I do that? Thanks.
Short answer: no.
Long answer: It's possible, but not in the way you're thinking. If a redirect to a login page is required, presumably that means the user is currently not authenticated. Send back a 401 response - this will indicate to the client that a login is required.
The trick now is to not handle the 401 in each call, but to handle it at some global point. For example, if you're using jQuery you can register a global error handler and check the status code - if it's a 401, then either redirect to the login page or otherwise accept authentication data.
You cannot do this on server side, since whatever you send will always be just AJAX response, while you want to redirect the whole page / browser tab (not just the AJAX request) to the login page.
The only way is to do this on client side in AJAX handler - send some flag (e.g. error status code) that you then handle in Javascript to redirect the whole browser tab to login page.
This will redirect the Ajax request to login page:
response.sendRedirect("/login.jsp");

Why does servlet name stay in url after RequestDispatcher.forward?

I am making a JSP/Servlet web app which starts with log in page.
After user enters log in information, a servlet, called LoginServlet, processes the data and if the log in is successful the servlet redirects user to MainPage.jsp like this:
RequestDispatcher rd = request.getRequestDispatcher("MainPage.jsp");
rd.forward(request,response);
It works. It takes me to MainPage.jsp, only the URL is NOT:
http://localhost:8080/RestauRec/MainPage.jsp
it is:
http://localhost:8080/RestauRec/LoginServlet
It is not an actual problem, but still, I want to know why this is and how can I change this?
Note: I don't know if it matters or not but, in the action attribute of the form element (in the log in page) I place LoginServlet. Like this:
<form action="LoginServlet" method="POST">
Thanks in advance!
forward is an action that happens within a single request-response cycle. It uses the forward-to resource to complete the response.
Your browser sends a single request to /someUrl and your server handles it, returning a response.
It is not an actual problem, but still, I want to know why this is and how can I change this?
You'd have to make your client, the browser, send a different request to another URL, possibly because of a redirect.
forward() method won't change the url. sendRedirect() in HttpServletResponse do change the url as well.
response.sendRedirect("MainPage.jsp");
Remember that a new request gets hit to the container when you do redirect. That means all the previous data vanishes and you'll get a brand new request.

Forward request to servlet using jquery which in turn forwards to jsp?

I have a js file and based on the below condition I need to display a message or forward the request to servlet which in turn forwards to jsp.
var isInIframe = (parent !== window),
if (isInIframe) {
//Forward request to servlet
}else {
//Display Access denied message
}
I can call a servlet using jquery ajax. But how can I forward request to servlet? once the request is forwarded to servlet then servlet will load some property files and forwards request to some.jsp as below.
//Keeps some values using request.setAttribute() then forward the request
request.getRequestDispatcher("/WEB-INF/some.jsp").forward(request, response);
How can i do that?
Thanks!
You can use Session for sending some objects to servlet. Because session remains same for the user throughout the application.
JQuery/Javascript does not "forward" requests to web applications. It makes new requests via AJAX or redirects. JQuery itself does not handle HTTP requests.
You need to make an AJAX request for this. I assume that JSP is the presentation layer of your web application. So just make an ajax request to your web app using the JQuery $.ajax() method..
You can handle the response using the AJAX callback function
Servlet and jsp are server-side components. The Server receives HTTP requests and dispatches a Servlet to handle them by producing a corresponding HTTP response for each of them, some times with the help of a jsp.
Javascript is a client-side component. It runs in the browser. When the javascript runs, the HTTP response containing the HTML you see in the browser has already been sent, so the Servlet is completely out of the picture. You cannot forward to it like you are imagining with
request.getRequestDispatcher("/WEB-INF/some.jsp").forward(request, response);
What you can do is use ajax to construct and send a new HTTP request that will be handled by a Servlet.

Using JSF 2.0 / Facelets, is there a way to attach a global listener to all AJAX calls?

Is there a way to attach a global listener to all AJAX calls in JSF? Maybe through a phase listener or something?
Here is the conundrum... Lets say you're using f:ajax tags and something like apache shiro and you let your session expire. Then you come back and click a button that has an f:ajax attached to it. The server will respond with a 302 redirect to the login page.
The user sees nothing. They can repeatedly click and invoke the ajax call, but to them the app is just "dead."
So, my though is, is there a way to attach a listener to all ajax calls in JSF? If so, what I'd like to do is monitoring the response code. If it's a redirect, use a window.navigate to send them along their way.
I'm always open to hear how others have solved this problem!
Is there a way to attach a global listener to all AJAX calls in JSF? Maybe through a phase listener or something?
Yes, a PhaseListener can do it. A SystemEventListener also. A Filter also.
If you're inside JSF context, then you can check as follows whether the current request is an ajax request or not.
if (FacesContext.getCurrentInstance().getPartialViewContext().isAjaxRequest()) {
// It's an ajax request.
}
If you're not inside JSF context, e.g. inside a Filter, then you can check as follows whether the current request is a JSF ajax request or not.
if ("partial/ajax".equals(request.getHeader("Faces-Request"))) {
// It's a JSF ajax request.
}
Here is the conundrum... Lets say you're using f:ajax tags and something like apache shiro and you let your session expire. Then you come back and click a button that has an f:ajax attached to it. The server will respond with a 302 redirect to the login page.
The user sees nothing. They can repeatedly click and invoke the ajax call, but to them the app is just "dead."
Forcing a redirect on an ajax request requires a special XML response. When you're inside JSF context, then ExternalContext#redirect() already takes this implicitly into account. All you need to do is to write this:
FacesContext.getCurrentInstance().getExternalContext().redirect(url);
If you're not inside JSF context, e.g. inside a Filter, then you'd need to write the whole XML response yourself. E.g.
response.setContentType("text/xml");
response.getWriter()
.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
.printf("<partial-response><redirect url=\"%s\"></redirect></partial-response>", url);
To redirect a jsf ajax request you need xml as follows
<?xml version="1.0" encoding="UTF-8"?>
<partial-response>
<redirect url="XXX">
</redirect>
</partial-response>
Here XXX is url you want redirect to happen.
On ajax call redirect sent is not as above hence no redirect.
To get the desired result have a filter for all jsf request except few
pages(login page) and check session is valid and if it is really jsf
ajax call by checking header "Faces-Request", its value should be
"partial/ajax". If session has expired and is ajax request send above
xml as response.
It should work.

Login page redirection in Java and Javascript

Ok, so I've got an interesting case of login page redirection going on.
My webservice has a login page (login.html) with some javascript to handle logging in and redirecting to a hardcoded 'default' page. The webservice is written in Java with a servlet filter handling redirection if a user is unauthenticated (so if a user tries to access domain/statistics without being logged in, they are directed to domain/login.html). The redirection from the protected services works: I can redirect to the login page and once a user is authenticated, redirect them to a default page. I am having issues, however, redirecting to the previous page.
I know this is usually handled with the argument document.referrer in the Javascript, which I have tried, but due to the Java's redirection with response.sendRedirect, the Referer header is not sent.
How can I get these two aspects to redirect to the previously called page? Is it something I need to add on the Javascript side, the Java side, or both?
What I've done is to drop the original (redirected) URL into a hidden input field on the login form. The code that does the authentication should just check that parameter, and if it's not empty it can redirect after establishing the session.
You have to be careful doing this to prevent XSS attacks etc., but it's not that hard and it works just fine.
In my framework (Stripes), I can push the original URL (taken from the HttpServletRequest object, a combination of the servlet path, the "path info", and the query string) into a special holding box that will cause the framework to give it back to me on the next request as a parameter. Without that, the simple thing to do is add the URL as a parameter when you redirect. Just URL-encode the original attempted URL and tack it onto the redirect URL with some parameter name. Then, on your login page, you just check for it:
<c:if test='${not empty param.attemptedUrl}'>
<input type='hidden' name='attemptedUrl' value='${fn:escapeXml(param.attemptedUrl)}'>
</c:if>
Then your login action will get that parameter too when the login form is submitted, and it can act on it as appropriate.
Send Redirect will ask to the client to repeat the request to the resource you choose. Have you think of Spring Security with minimal configuration you can achieve this quite easily.
Take a look at this:
http://static.springsource.org/spring-security/site/docs/3.0.x/reference/ns-config.html

Categories

Resources