根据Java EE标准,Tomcat允许请求以两种方式指定其现有会话ID:1)通过cookie; 2)通过“路径参数”(不是常规参数;路径参数具有格式http://host/path/file.ext;jsessionid=xxx?a=b&c=d...
- 注意“;”以及查询字符串仅在路径参数之后开始的事实)。我想要的是将请求中的会话ID作为REGULAR参数传递到“?”之后的查询字符串中,如http://host/path/file.ext?jsessionid=xxx
。
当请求到达我可以拦截它的地方并改变容器确定会话ID的方式时(例如在Filter或Servlet中),这已经太晚了。我想要改变的行为是在客户端的请求的初始处理中。我想避免做的是改变Coyote或Tomcat代码并自己重建Tomcat,原因很明显。我更喜欢做的是覆盖相应的代码并配置Tomcat以使用该代码来确定所请求的会话ID。这似乎不可能,但我希望我错了。
我知道以这种方式获取会话ID是非标准的;我知道使用cookie或路径参数都是跟踪会话状态的好方法;我知道将会话ID放在实际的查询字符串中会带来潜在的问题。无论如何我还是需要这样做。
运行Tomcat 7,顺便说一下。
答案 0 :(得分:1)
最简单的方法是从源代码构建Tomcat,并破解CoyoteAdapter.java类。
这是代码所在的位置,但它不在代码中易于扩展的部分,您可以插入一些代码来拦截请求管道的这一部分。
你可以聪明地实现你自己的连接器,它依赖于你自己的CoyoteAdapter,而不仅仅是“就地”黑客攻击它,但最终你仍然会遇到维护问题,无法跟上更新等等。 / p>
你还需要小心,因为通常请求参数不会被“解析”,直到有人要求它们,并且通常直到实际的用户代码才会这样做(我不相信它在点击之前在管道中完成用户代码)。
这很重要,因为对于GET,参数解析是在请求标头之外完成的,对于POST,它基于内容。如果您询问参数的请求,它不关心它是POST还是GET,并且会自动“做正确的事情”。
这意味着如果从POST请求请求参数,管道将在用户应用程序代码之前消耗输入流(在标题之后开始指向请求有效负载)。取决于用例,但有些应用程序需要原始流,因此您必须小心使用内置的请求参数逻辑,而不是使用原始URL本身。
你也可以通过一个简单的过滤器来解决这个问题,然后你就可以将HttpServletRequest转换为底层的Tomcat实现(此时我的名字不在我身上),然后在其上调用“setSessionID”代码。 Dunno如果在处理周期中为时已晚,可能就是这样。
所以,它可以完成,而不是简单地看,但不是通过任何真正规定的扩展方式。官方方法是克隆tomcat连接器以调用您自己的CoyoteAdapter版本,并在server.xml中进行配置。但是如果你愿意维护你自己的tomcat版本,直接黑客CoyoteAdapter将会容易得多。
答案 1 :(得分:0)
您可以在不更改任何 Tomcat 代码的情况下执行此操作。这是一个示例 http 过滤器。显然它应该在任何其他过滤器之前运行:
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
final String sessionId = servletRequest.getParameter("jsessionId");
if (servletRequest instanceof org.apache.catalina.connector.RequestFacade) {
try {
Field tomcatRequestField = servletRequest.getClass().getDeclaredField("request");
tomcatRequestField.setAccessible(true);
Request tomcatRequest = (Request) tomcatRequestField.get(servletRequest);
if (sessionId != null) {
tomcatRequest.setRequestedSessionId(sessionId);
}
} catch (NoSuchFieldException | IllegalAccessException e) {
LOG.error("Error", e);
}
}
filterChain.doFilter(servletRequest,servletResponse);
}