引言
由于最近在做应用集成平台,即实现独立部署的WAR包可以在同一个集成平台中访问。被集成的业务组件为什么可以在集成平台实现页面集成,主要通过以下几个步骤实现:
①用户登录集成平台系统;
②集成平台加载业务组件菜单,业务组件菜单的URL自动添加一个会话凭据,即会话token。这样点击这个组件菜单,将向独立部署的业务组件服务发送页面请求;
③这个页面请求被安装在业务组件中的集成插件(其实是一个HttpFilter)截获,并执行以下操作:
1)集成插件通过向集成平台发送REST请求验证token的合法性,如果不合法将请求重定向
到集成平台的登录页面,否则执行下一步操作;
2)根据token再次发送REST请求,获取对应的会话用户信息(如用户名,所有单位等)。
④根据远程获取的用户会话信息产生业务组件本地的会话(即本地的HttpSession),创建本地会话后,即可正常打开被集成到集成平台的业务组件菜单页面了。
图1 平台集成结构图
由于集成平台提供的验证token合法性、根据token获取会话用户信息等Rest服务都是工作于会话环境下,因此我的设计是token即取自会话的ID(即HttpSession.getId()),换句话说,token即是会话的ID。在集成插件中,通过发送如下的Rest请求调用集成平台的Web Service:
http://<集成平台url>;jsessionid=<token>?xxx=yyy... |
以下是通过URL传递会话的标准写法,在Jetty,Tomcat等应用服务器下,集成平台都可为请求正确绑定HttpSession,但是在WebSphere下却不行,为了解决该问题花了我两天多时间,下面就回顾一下解决这个问题的整体过程。
Websphere默认未开启URL会话重写
我们都知道维护客户端和服务端会话有两种实现方式,其一是通过URL会话重写,即上面所列的URL后加“;jsessionid=xxx”的方式,另一种是通过Cookie,在产生会话时,应用服务器向客户端Cookie中写一个名为JSESSIONID的会话ID,客户端每次请求时都将Cookie带上来,以下是一个会话Cookie的报文:
图 2 Cookie会话ID
Jetty,Tomcat等应用服务器默认两种方式都支持,但是WebSphere默认只支持Cookie维护会话的方式,如果需要支持URL会话重写的方式,需要手工启用这个功能并重启应用服务器:
由于我的集成插件默认是以添加";jsessionid=xxx"来维护会话的,由于WebSphere默认未开启URL会话重写,我又不希望对应用服务器的配置提出额外的要求,
因此决定放弃URL重写方式,统一采用Cookie维护会话。因此集成插件做了如下的调整:
public String doGet(String url, String token) { CloseableHttpResponse response = null; try { if (logger.isDebugEnabled()) { String message = MessageFormat.format("doGet[request]:\n[{0}]", url); logger.debug(message); } HttpGet httpGet = new HttpGet(url); httpGet.addHeader(new BasicHeader("Cookie", "JSESSIONID=" + token));//==>①这儿通过Cookie上传会话ID httpGet.setConfig(requestConfig); response = httpClient.execute(httpGet); HttpEntity entity = response.getEntity(); String result = EntityUtils.toString(entity, Consts.UTF_8); if (logger.isDebugEnabled()) { String message = MessageFormat.format("doGet[response]:\n[{0}]", result); logger.debug(message); } return result; } catch (IOException e) { logger.error("doGet error", e); throw new RuntimeException(e); } finally { try { if (response != null) { response.close(); } } catch (IOException e) { logger.error("doGet error", e); throw new RuntimeException(e); } } }
本以为这样就可以万事大吉了,可是还是使用Jetty,Tomcat运行集成平台时都是正常的,但是使用WebSphere时还是外甥打灯笼--照旧,依然顽强地一点击被集成组件菜单就弹出到集成平台的登录页面。
Websphere奇葩的会话ID
一般应用服务器通过HttpSession.getId()获取的ID和其自动被Cookie中写的JSESSIONID是一致的,可是WebSphere毕竟不是常人,它非常有个性的两者不一致。也就是说你在服务器获取的会话ID和它写到客户端的会话ID是不一致的,而且如果你手工将服务端获取的会话ID放到Cookie中的JSESSIONID中时,服务端无法找到对应的会话!!!!!,我不想让人说我诬陷IBM,有图为证:
图4 WebSphere Cookie的会话ID和服务端获取不一致
且不说 WebSphere往Cookie中写的一大坨内容究竟有没有必要(tomcat,jetty的cookie都是清清爽爽的),它往Cookie中写的会话ID不是服务器端
通过HttpSession.getId()获取的会话ID,而是头尾都加了东西:头部添加了“0000”,尾部添加了:19vrbkigt(不知道啥用途)!如果要通过Cookie维护
会话,一定要学WebSphere在会话ID前添加“0000”,否则请求发上去就找不到对应的会话了。
由于Jetty的会话ID为12位,Tomcat的会话32位,而webSphere的会话ID(服务端的)23位,所以我就根据会话ID长度来识别是哪咱类型应用服务器的会话ID
,如果是websphere的就在前面添加0000,代码如下:
/** * 对{@code token}进行处理: * <pre> * 1.was 的token前面需要添加0000:xxx=>0000xxx * 2.jetty,tomcat,等其它应用服务器直接返回原值. * 注意:was的token为23位,jetty及tomcat的token分别为12及32位. * </pre> * @param token * @return */ private static final String getNormToken(String token) { if (token != null && token.length() == 23) { return "0000"+token; }else{ return token; } }
小结
WebSphere不死,程序灾难未平!
相关推荐
快捷设置Websphere的超时问题,永久会话的设置问题统统解决!
使用WebSphere MQ管理远程队列管理器.doc
关于 WebSphere 的应用部署关于 WebSphere 的应用部署
WebSphere内存管理 java开发需要注意地方
WEBSPHERE开发与管理 高清 v6
中文版的Websphere Portal开发格式PDF格式
关于WebSphere建立jdbc数据源
使用概要文件简化 WebSphere Application Server 管理
websphere mq 7.1 通道授权问题解决办法
WebSphere MQ 系统管理指南 6.0 中文版
WebSphere开发与管理 WebSphere开发与管理
WEBSPHERE开发与管理+涂传滨,邱丽娟 高清 在淘宝上5块买的 websphere v6
第二部分 Websphere MQ系统管理 43 第三章WebSphere MQ系统安装 43 目标 43 3.1 规划安装 43 3.1.1 硬件要求 43 3.1.2 软件要求 44 3.2 安装 WebSphere MQ 46 3.2.1 WebSphere MQ 文档 46 3.2.2 WebSphere MQ安装 47...
webSphere指南webSphere指南webSphere指南webSphere指南webSphere指南
Websphere WAS IBM 服务器 管理 配置 Websphere WAS IBM 服务器 管理 配置 Websphere WAS IBM 服务器 管理 配置 Websphere WAS IBM 服务器 管理 配置
websphere cpu性能问题 文档
详细介绍了如何安装websphere软件平台,如何在上面发布包并能成功运行系统,如何正确卸载websphere等。
WebSphere开发与管理_源代码
websphere 安全管理
Websphere 中生成日志问题