Question

I've got some strange bug: when I open page first time in some browser all references has jsessionid parameter (like <a href="/articles?name=art&jsessionid=5as45df4as5df"..>).

When I press F5 or refresh the page by any other ways all that stuff is disappeared and everything works fine until I close my browser (and all tabs should be closed too). When I open it again I see this strange jsessionid parameter.

I use jstl <c:url..> tag for creating all URLs.

I've read some time ago that jsessionid is an alternative to cookies if cookies are disabled, but cookies are enabled and I actually don't use cookies.

Was it helpful?

Solution

This isn't a bug, it's by design. When a new session is created, the server isn't sure if the client supports cookies or not, and so it generates a cookie as well as the jsessionid on the URL. When the client comes back the second time, and presents the cookie, the server knows the jsessionid isn't necessary, and drops it for the rest of the session. If the client comes back with no cookie, then the server needs to continue to use jsessionid rewriting.

You may not explicitly use cookies, but you do implicitly have a session, and the container needs to track that session.

OTHER TIPS

As explained in skaffman's answer, its not a bug. Its an expected behavior.

In your question the jsessionid is appended as a parameter, which is not the case.
Using
<c:url value="/"/>
will generate something like the following: /some/;jsessionid=E85FAC04E331FFCA55549B10B7C7A4FA.
So using
<link href="<c:url value="/"/>stylesheets/style.css" rel="stylesheet" type="text/css"/>
will generate
/some/;jsessionid=E85FAC04E331FFCA55549B10B7C7A4FAstylesheets/style.css
, so your server cannot find the resource available.

The best workaround that I found is to use ${pageContext.request.contextPath} instead of <c:url value="/"/>. So in the previous example, you would have
<link href="${pageContext.request.contextPath}/stylesheets/style.css" rel="stylesheet" type="text/css"/>
that will generate
/some/stylesheets/style.css.

This solution is container independent (whereas the servlet specification v3 compliant container - like Tomcat - solution is not). Filtering the response url feels like a hack, cause you need to change a default behavior. But all depends on what you need and want to achieve.

On Tomcat 7 or any servlet specification v3 compliant server you can disable jsessionid in URL by adding following to the web.xml of your application

<session-config>
    <tracking-mode>COOKIE</tracking-mode>
</session-config>

Here's a nasty workaround in flavor of a Filter so that you will never see the jsessionid in URL whenever the client supports cookies.

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;
    HttpSession session = req.getSession();

    if (session.isNew()) {
        // New session? OK, redirect to encoded URL with jsessionid in it (and implicitly also set cookie).
        res.sendRedirect(res.encodeRedirectURL(req.getRequestURI()));
        return;
    } else if (session.getAttribute("verified") == null) {
        // Session has not been verified yet? OK, mark it verified so that we don't need to repeat this.
        session.setAttribute("verified", true);
        if (req.isRequestedSessionIdFromCookie()) {
            // Supports cookies? OK, redirect to unencoded URL to get rid of jsessionid in URL.
            res.sendRedirect(req.getRequestURI().split(";")[0]);
            return;
        }
    }

    chain.doFilter(request, response);
}

Map it on /* or whatever URL pattern which require session management.

If you have a common wrapper page that all pages use (for me it was common.inc) you can add session="false" to your <%@ page to remove the sessionid.

Example common.inc

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" session="false" trimDirectiveWhitespaces="true" %>
<%@ taglib prefix="ab" tagdir="/WEB-INF/tags" %>

<c:set var="contextPath" scope="request" value="${ pageContext.request.contextPath }" />
<c:set var="assetPath" scope="request" value="/assets" />
<c:set var="debugEnabled" scope="request" value="${ applicationDebugProperties.debugEnabled }" />

Alternatively.. set the value of c:url to a variable and use c:out escapeXml="false" to output the variable and this will remove the sessionid.

Example:

<c:url value=${url} var="image"/>
<c:out var=${image} escapeXml="false"/>

Alternatively, you can add this to your Apache configuration to truncate the sessionid.

ReWriteRule ^/(\w+);jsessionid=\w+$ /$1 [L,R=301]
ReWriteRule ^/(\w+\.go);jsessionid=\w+$ /$1 [L,R=301]

Unfortunately the only way I have found around this is to add a filter to your application that will strip out the jsessionid parameter. Its particularly annoying if you are creatinga public website and want th esearch engines to index your pages.

I do not believe that tomcat (if that's what you're using) can be configured to not add this to your url. I can't say for the other servers though.

However, note that if you do create the filter and you then require session management and the user has cookies turned off you will run into problems.

One workaround is not to use <c:url>, but to use ${request.contextPath}/path

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top