JSessionId ocorre em todos os URLs que são gerados por jstl tag
-
20-08-2019 - |
Pergunta
Eu tenho um bug estranho: quando abro a página pela primeira vez em algum navegador, todas as referências tem o parâmetro JSessionID (como <a href="/articles?name=art&jsessionid=5as45df4as5df"..>
).
Quando pressiono a F5 ou atualizo a página de qualquer outra maneira, tudo o que é desaparecido e tudo funciona bem até eu fechar meu navegador (e todas as guias também devem ser fechadas). Quando abro novamente, vejo esse estranho parâmetro JSessionID.
Eu uso JSTL <c:url..>
tag para criar todos os URLs.
Eu li há algum tempo que o JSessionID é uma alternativa aos cookies se os cookies estiverem desativados, mas os cookies estão ativados e eu realmente não uso cookies.
Solução
Isso não é um bug, é por design. Quando uma nova sessão é criada, o servidor não tem certeza se o cliente suporta cookies ou não, e, portanto, gera um cookie e o JSessionID no URL. Quando o cliente volta pela segunda vez e apresenta o cookie, o servidor sabe que o JSessionID não é necessário e o retira pelo restante da sessão. Se o cliente voltar sem cookie, o servidor precisará continuar usando a reescrita do JSessionID.
Você não pode usar explicitamente cookies, mas tem uma sessão implicitamente e o contêiner precisa rastrear essa sessão.
Outras dicas
Conforme explicado Resposta de Skaffman, não é um bug. É um comportamento esperado.
Em sua pergunta, o JSessionID é anexado como um parâmetro, o que não é o caso.
Usando
<c:url value="/"/>
irá gerar algo como o seguinte: /some/;jsessionid=E85FAC04E331FFCA55549B10B7C7A4FA
.
Então usando
<link href="<c:url value="/"/>stylesheets/style.css" rel="stylesheet" type="text/css"/>
irá gerar
/some/;jsessionid=E85FAC04E331FFCA55549B10B7C7A4FAstylesheets/style.css
, para que seu servidor não possa encontrar o recurso disponível.
A melhor solução alternativa que encontrei é usar ${pageContext.request.contextPath}
ao invés de <c:url value="/"/>
. Então, no exemplo anterior, você teria
<link href="${pageContext.request.contextPath}/stylesheets/style.css" rel="stylesheet" type="text/css"/>
isso vai gerar
/some/stylesheets/style.css
.
Esta solução é Independente do contêiner (enquanto a especificação do servlet v3 contêiner compatível - como o tomcat - a solução não é). Filtrar o URL de resposta parece um hack, porque você precisa alterar um comportamento padrão. Mas tudo depende do que você precisa e deseja alcançar.
No Tomcat 7 ou em qualquer servidor de especificação de servlet v3, você pode desativar o JSessionID no URL adicionando seguidores ao web.xml do seu aplicativo
<session-config>
<tracking-mode>COOKIE</tracking-mode>
</session-config>
Aqui está uma solução alternativa desagradável em sabor de um Filter
Para que você nunca verá o JSessionID no URL sempre que o cliente suporta 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);
}
Mapeie -o /*
ou qualquer padrão de URL que exija gerenciamento de sessões.
Se você tem uma página de wrapper comum que todas as páginas usam (para mim era comum.inc), você pode adicionar session="false"
para o seu <%@ page
Para remover o SessionID.
Exemplo 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 }" />
Alternativamente .. Defina o valor de c:url
para uma variável e uso c:out escapeXml="false"
Para produzir a variável e isso removerá o SessionID.
Exemplo:
<c:url value=${url} var="image"/>
<c:out var=${image} escapeXml="false"/>
Como alternativa, você pode adicionar isso à sua configuração do Apache para truncar o SessionID.
ReWriteRule ^/(\w+);jsessionid=\w+$ /$1 [L,R=301]
ReWriteRule ^/(\w+\.go);jsessionid=\w+$ /$1 [L,R=301]
Infelizmente, a única maneira que encontrei em torno disso é adicionar um filtro ao seu aplicativo que retirará o parâmetro JSessionID. É particularmente irritante se você estiver criando um site público e deseja que os mecanismos de pesquisa indexem suas páginas.
Não acredito que o Tomcat (se é isso que você está usando) pode ser configurado para não adicionar isso ao seu URL. Eu não posso dizer para os outros servidores.
No entanto, observe que, se você criar o filtro e precisar de gerenciamento de sessão e o usuário tiver cookies desligados, você terá problemas.
Uma solução alternativa não é usar <c:url>
, mas para usar ${request.contextPath}/path