JSF wrong redirection when catching ViewExpiredException - url

So I have a ViewExpiredException Handler and works fine.
Now, when I launch the web-app my URL looks like www.myApp.com/TestFaces/ and this presents the first page which is the login page.
If for any reason I leave the page at login, and the View expires the app catches the ViewExpiredException and sends me to a page "ViewExpired" BUT the URL keeps the same www.myApp.com/TestFaces/. On that "ViewExpired" page I have a commandLink to return to the login page which in the value attrib I put "index.xhtml" BUT it does not send me to login page because on there's no page on www.myApp.com/TestFaces/index.xhtml but in www.myApp.com/TestFaces/faces/index.xhtml
So the questions are:
Why if I'm at login page am I getting the ViewExpiredException? is it because of ajax?
How or Where can I make the commandLink really sends me to index.xhtml?
This is only happening when the View expires in login page, in other pages from my app it works really great.
Thanks in advance !

Why if I'm at login page am I getting the ViewExpiredException? is it because of ajax?
You will get this exception when you invoke a POST request on a view which does not exist in session anymore. This can for example happen when you keep the page open for too long that the session has expired in the server side, or when you're getting the login page from the browser cache instead of straight from the server. For more detail, see also our ViewExpiredException tag info page. All JSF ajax requests also accounts in this as they also use POST.
How or Where can I make the commandLink really sends me to index.xhtml?
Make use of implicit navigation. This way JSF will append the proper FacesServlet mapping.
public String goToIndexPage() {
return "index";
}
or
<h:commandLink value="Go to index page" action="index" />
or, better, when you don't need to invoke any business logic at all:
<h:link value="Go to index page" outcome="index" />
See also:
Check if session exists JSF
When should I use h:outputLink instead of h:commandLink?

Related

Return to previous page in ASP.Net Core MVC

From my client detail page I have a button to edit the client record which redirects to an edit page. I have a "return to client detail" link on the edit page which I want to redirect the user back to the previous client detail page.
<a asp-controller="Client" asp-action="Detail" asp-route-id="#Model.ClientID">Return to client detail</a>
Currently this works as expected but takes extra time as it reloads the detail page from scratch (ie running all the various db queries again). Since the user is really just cancelling the edit without any changes to the state of the client I am wanting to return the user to the previous detail page without having to go through the controller action again.
Essentially I am wanting to simulate the browser back button (to improve responsiveness) but i'm not sure how to implement this or whether it's good practice to do so. Some guidance would be appreciated.
Thanks
For IActionResult you can use this code:
public IActionResult Test()
{
return Redirect(Request.Headers["Referer"].ToString());
}
U know what? I hate JS so i will write answer with backend side. The HTTP referer is an HTTP header field that identifies the address of the webpage that linked to the resource being requested. So simply read that and pass to view (always remember about XSS and validation, user can easly spoof HTTP request)
In action controller
if(Request.Headers["Referer"] != null)
{
ViewData["Reffer"] = Request.Headers["Referer"].ToString();
}
In view (razor)
#if(!string.IsNullOrWhiteSpace(ViewData["Reffer"]))
{
Return to client detail
}
You can use
<a href='javascript:history.go(-1)'>Return to client detail</a>
or onclick
Return to client detail
It should be like this
<input type="button" onclick= "history.go(-1)" value="Return to client detail" />
One note of caution using Request.Headers["Referer"] - if someone refreshes the destination page for some reason, Request.Headers["Referer"] will be empty.
Using history.go(-1) gives the expected behavior despite page refresh.
I think that you need to get rid of the idea of passing through the controller. If you need to browse quickliest with asp net core code about href you can try this.
<a asp-area="" onclick="history.go(-1);">Return to client detail</a>
I would never rely on my button, thinking a user will prefer it to browser back button.
I would say the correct way to solve this problem is to store the page state somewhere, for example, save ViewModel in TempData or Session. Then, if exists, load from it, instead of running db queries. It's quick and reliable.
This Request.Headers["Referer"] will not work if the user refresh the page or the page is been loaded twice, which mean, clicking back will not take you out of the current page.

CommandLink action redirect to external url not working

I am using jsf 2. I have a link in a facelet file that points to a external url. My current view is /app1/home.xhtml with a h:commandLink that has an action like so
<h:commandLink value="#{link}" action="#{action.redirect}" target="_blank"/>
the url that action.redirect redirects to is /app2/info.do. However it appears that JSF tries to change the extension of the url to .xhtml. and then fails with the error message.
com.sun.faces.context.FacesFileNotFoundException: /app2/info.xhtml Not Found in ExternalContext as a Resource
how do i get this to correctly redirect ?
Don't use the <h:commandLink> here, it's the wrong tag for the purpose. It is designed to submit a JSF POST form and navigate to a JSF view, both which you obviously don't want to let take place in this particular use case.
Just use the <h:outputLink> or even plain HTML <a>. So,
<h:outputLink value="#{action.redirect}" target="_blank">#{link}</h:outputLink>
or
#{link}
Note that you don't need the <h:form> in both approaches.

synchronisation of pages in address bar in a web application using jsf2

I'm working in a jsf2 application and I have a problem with the page name displayed in the address bar. When I navigate to an other page I have in address bar the name of the previous page.
Thanks.
That's because you're using POST instead of GET for page-to-page navigation and JSF defaults to submitting to the very same view with you're using <h:form>. Using POST for page-to-page navigation is in any case a very poor approach. It's not only not user friendly (it's not bookmarkable and confusing), but it's also not SEO friendly (searchbots don't follow <form> actions).
To solve this problem, you must stop using <h:commandLink> for page-to-page navigation. Use <h:link> instead.
<h:link value="Go to next page" outcome="nextpage" />
This will just render a
Go to next page
Which is perfectly bookmarkable, user friendly and SEO friendly.
When you're navigating to a different page as result of a real POST form submit, I'd also replace that by returning null or void and just render the result/messages conditionally in the very same view. Or if the result is supposed to be bookmarkable (e.g. search results), you should use normal links or plain <form> instead of <h:form> and use <f:viewParam> in target view.
See also:
When should I use h:outputLink instead of h:commandLink?
This is happerning because, in JSF, when you are navigating to a new page the server is performing a forward to the new page. The browser is unaware of the forwarding and is displaying the old url. To make the server perform a redirect instead of forwarding, you have to either:
If you are using navigation rules, add a <redirect/> to each rule:
<navigation-rule>
<from-view-id>/pages/from.xhtml</from-view-id>
<navigation-case>
<from-outcome>to</from-outcome>
<to-view-id>/pages/to.xhtml</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
If you are returning an outcome from a bean method, add a ?faces-redirect=true to the outcome:
public String navigate() {
return "/pages/to?faces-redirect=true";
}

JSF login forward address bar / url -- redirect does not solve problem

Okay we have a single - sign - on and the user will likely enter www.blabla.com/AppName/ to reach our site. We then define a welcome site, use a phaselistener to check:
is user trying to access the welcome site? yes -> try to login - works? yes -> get user roles -> forward to the appropriate site for this specific user.
E.g. user niceBelly goes to page /somewhere/in/many/folders/beer.jsf and user barbie goes to /breasts/pink.jsf
a redirect is in this application not possible for some reasons.
the result is that when reaching e.g. page pink.jsf the address bar still shows blablaba.com/AppName/
clicking the first link will result in the browser using the form address as new URL e.g. on welcome.jsf i navigate to coolstuff.jsf. On the page coolstuff i now have the url of the last form, e.g. welcome.jsf. Then on cool stuff i click a link, and get coolstuff on the next page as url, and so on.
Is there a way to solve this / work around it?
Given the symptoms, you are actually not redirecting the requests, but you are actually forwarding the requests. A real redirect will take place when you call
externalContext.redirect(url);
in JSF context, or when you add
<redirect />
to the navigation case. All other ways are effectively forwards. As per the symptoms, you're using commandlinks instead of outputlinks to navigate to other page. Commandlinks will submit a POST request to current URL and JSF will under the covers use RequestDispatcher to set the destination of the request/response when the navigation case doesn't contain <redirect />. A forward does not instruct the browser to fire a new GET request on the destination URL and hence the URL in browser address bar does not change. A real redirect will do exactly that.
See also:
When should I use outputlink instead of commandlink?
Bookmarkable URLs in JSF 1.x

Problem with HttpSession in Struts2

I am doing a multi user login application where I use session to store the user object.
HttpSession session = request.getSession(true);
session.setAttribute("user",user);
In every page I am checking using JSTL whether the user object is present in the session.
<c:choose>
<c:when test="${not empty sessionScope.user}">
//jsp code
</c:when>
<c:otherwise>
<logic:redirect forward="welcome"/>
</c:otherwise>
</c:choose>
My problem is that if the user clicks on a href link in the application the user changes to Previous user in the session. i.e. the it is loading the user from cache. If I refresh the page it will load the correct user.
How could I fix it?
If you are using Struts2 it might make more sense to have that check in an Interceptor instead of repeating the code in every JSP.
http://struts.apache.org/2.0.11/docs/interceptors.html
Nate is right, this is best handled in an Interceptor. This answer may be of use to you.
Edit
It sounds like this might be a page caching issue, then. Try setting a breakpoint in your Java code so that you can inspect what the user object in the session is. Assuming that the user object is always correct and it is just the page showing incorrect information, then try setting no-cache headers as detailed here.

Resources