JsessionId - как избежать: jsessionid = XXX при первом вызове страницы? он работает, если первая страница - jsp
Ну, я закончил с этим...
У меня есть приложение, которое использует
приветствующая страница index.jsp с <iframe></iframe>
содержимым iframe является страницей jsf. Если я обращаюсь к index.jsp, я вижу cookie уже на первом входе в firebug:
Set-Cookie JSESSIONID=C615DA89B6EF73F801973EA3DCD3B226; Path=/
Страница <iframe>
наследует этот jsessionid. НО: когда я напрямую обращаюсь к странице <iframe/>
, я получаю jsessionId, переписанную ко всем URL-адресам без файла cookie - по первому запросу. Затем используется файл cookie. Все в порядке - если:
Система безопасности позволит мне выполнять перезапись URL.
Я запускаю jboss 4.2.2
Я хочу добиться такого же поведения, как у меня с index.jsp - например. всегда используйте файлы cookie и всегда избегайте перезаписи http.
[EDIT]
Благодаря балюсному ответу я написал следующее:
public class JsessionIdAvoiderFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
ServletException {
boolean allowFilterChain = redirectToAvoidJsessionId((HttpServletRequest) req, (HttpServletResponse)res);
//I'm doing this because if I execute the request completely, it will perform a pretty heavy lookup operation. No need to do it twice.
if(allowFilterChain)
chain.doFilter(req, res);
}
public static boolean redirectToAvoidJsessionId(HttpServletRequest req, HttpServletResponse res) {
HttpSession s = req.getSession();
if(s.isNew()) {
//after the redirect we don't want to redirect again.
if(!(req.isRequestedSessionIdFromCookie()&&req.isRequestedSessionIdFromURL()))
{
//yeah we have request parameters actually on that request.
String qs = req.getQueryString();
String requestURI = req.getRequestURI();
try {
res.sendRedirect(requestURI+"?"+qs);
return false;
} catch (IOException e) {
logger.error("Error sending redirect. " + e.getMessage());
}
}
}
return true;
}
}
Не забудьте добавить его в свой web.xml
<filter>
<display-name>JsessionId Filter</display-name>
<filter-name>jsessionIdAvoiderFilter</filter-name>
<filter-class>my.namespace.JsessionIdAvoiderFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>jsessionIdAvoiderFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
Ответы
Ответ 1
С сервлета 3.0 вы можете использовать <tracking-mode>COOKIE</tracking-mode>
для этого. Но поскольку JBoss 4.2.2 не является компилятором Servlet 3.0, это не вариант.
Проще всего было бы создать фильтр сервлета, который отправляет перенаправление на HttpServletRequest#getRequestURI()
, когда HttpSession#isNew()
возвращает true
. Не забудьте проверить HttpServletRequest#isRequestedSessionIdFromCookie()
, чтобы предотвратить бесконечный цикл переадресации, когда клиент вообще не поддерживает файлы cookie.
Ответ 2
Основываясь на рекомендации Кристофера Шульца, я пробовал это, и он работает.
package com.rama.test.jsessionfilter
public class JsessionIdAvoiderFilter implements Filter {
protected static final Logger LOGGER = LogManager.getLogger(JsessionIdAvoiderFilter.class);
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
if (!(req instanceof HttpServletRequest)) {
chain.doFilter(req, res);
return;
}
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// Redirect requests with JSESSIONID in URL to clean old links
/* If you really want clean up some old links which have Jsession id bookmarked clean it. If its new app
this below check is not required. */
if (request.isRequestedSessionIdFromURL()) {
String url = request.getRequestURL().append(request.getQueryString() != null ? "?"
+ request.getQueryString() : "").toString();
response.setHeader("Location", url);
response.sendError(HttpServletResponse.SC_MOVED_PERMANENTLY);
LOGGER.info(" Found url with jsession id in it:"+ request.getRequestURL() +": url="+url);
return;
}
// Prevent rendering of JSESSIONID in URLs for all outgoing links
HttpServletResponseWrapper wrappedResponse = new HttpServletResponseWrapper(
response) {
@Override
public String encodeRedirectUrl(String url) {
return url;
}
@Override
public String encodeRedirectURL(String url) {
return url;
}
@Override
public String encodeUrl(String url) {
return url;
}
@Override
public String encodeURL(String url) {
return url;
}
};
chain.doFilter(req, wrappedResponse);
}
public void destroy() {
}
public void init(FilterConfig arg0) throws ServletException {
}
}
и следующую запись в web.xml
<filter>
<display-name>JsessionId Filter</display-name>
<filter-name>jsessionIdAvoiderFilter</filter-name>
<filter-class>com.rama.test.jsessionfilter.JsessionIdAvoiderFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>jsessionIdAvoiderFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
Отлично работает!!!.
Ответ 3
Это можно сделать с помощью простого фильтра, который завершает запрос с помощью HttpServletRequest, который переопределяет HttpServletRequest.encodeURL и HttpServletRequest.encodeRedirectURL. Просто верните аргумент String, переданный ему, и вы отключите повторную запись URL. Обратите внимание, что это будет работать только для одного веб-приложения, если вы не хотите либо настроить его в conf/web.xml
(не рекомендуется), либо настроить его во всех ваших отдельных веб-папках.
Этот метод превосходит тот, который опубликован позже в вашем вопросе, потому что он не требует перенаправления, что может замедлить ваши запросы. ИМО, он также более чист.