最近在折腾一个旧系统,从IE浏览器搬到谷歌浏览器。这当然是没法直接搬的,主要是依赖了一个谷歌插件IETab,对部分无法兼容的Struts2/JSP页面菜单采用IETab打开,遇到了一个奇怪事情,页面上的有些图标显示不出来,下面记录一下主要的定位过程和原因分析。
一开始的时候,我就注意到有些菜单里边的图标实现不了,但也不是必现的,有些菜单就是可以的,所以没留意这个问题。后来其他人也发现了,才发现只有在IETab打开某些菜单才会。
看来一下请求的路径,发现是图标是404,调用路径是a.gif;jessionid=xxxxx的格式。的确这种路径会在当前nginx配置下被拦掉,但我点一下查询,页面刷一刷图标就正常了。还好是搞过JSP/Servlet的,我意识到这个机制是采用URL重写来传递会话标识,在Cookie会话标识不存在的情况下会有这种情况。
了解到这点,后面也很快理清楚整个过程了。这个系统外层路径是/a,通过iframe打开真实菜单路径/b,首先/b这里打开的是一个JSP页面,这个图标是在一个JSP标签上生成的,生成URL的时候调用了response.encodeURL,这就可能出现URL重写情况。另外,IEtab免费版不支持打开IE时传递Cookie信息,虽然我们用来一定的手段把Cookie传递到/a了,但是/b的会话没有带过来,所以打开/b的同时生成图标路径的时候,就出现了URL重写。
以前不存在会话带不过去的问题,这也能解释,为什么换成IETab之后这个问题变得很明显了。
这是一个旧应用,会话是必须的,配置也不能随便动,最终打了个小补丁:在打开/a的时候,先在页面提前访问一下/b的一个简单路径,这样/b的会话标识有了,再打开菜单就正常显示图标了。
虽然现在已经不流行JSP了,但JSP还是相当强大的。定位过程顺手翻了一下encodeURL在tomcat的具体实现,顿时又有点怀念了。
源码跟踪记录
主要源码在org.apache.catalina.connector.Response。
@Override
public String encodeURL(String url) {
...
if (isEncodeable(absolute)) {
...
return toEncoded(url, request.getSessionInternal().getIdInternal());
}
...
}
核心方法就逻辑就在这两段,isEncodeable判断要不要对URL编码,toEncoded对URL进行编码。
protected boolean isEncodeable(final String location) {
...
// Are we in a valid session that is not using cookies?
final Request hreq = request;
final Session session = hreq.getSessionInternal(false);
if (session == null) {
return false;
}
if (hreq.isRequestedSessionIdFromCookie()) {
return false;
}
// Is URL encoding permitted
if (!hreq.getServletContext().getEffectiveSessionTrackingModes().
contains(SessionTrackingMode.URL)) {
return false;
}
...
}
判断要不要编码也很简单,判断有没有会话,如果有会话判断在Cookie中有没有会话ID。如果没有会话ID,看支不支持URL会话跟踪,只有支持这个特性的情况下才需要考虑URL编码。
会话跟踪特性介绍:
-
https://stackoverflow.com/questions/16262285/set-tracking-mode-to-cookie-to-remove-appended-session-id-without-using-web-xml -
https://www.logicbig.com/tutorials/java-ee-tutorial/java-servlet/session-tracking-mode.html
protected String toEncoded(String url, String sessionId) {
...
StringBuilder sb = new StringBuilder(path);
if( sb.length() > 0 ) { // jsessionid can't be first.
sb.append(';');
sb.append(SessionConfig.getSessionUriParamName(
request.getContext()));
sb.append('=');
sb.append(sessionId);
}
...
}
编码的方式就是在路径后面加上在加上;jessionid=xxxx的路径。
原文始发于微信公众号(程序员的胡思乱想):图标丢失,URL带上jsessionid是什么鬼?
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/22606.html