33

我有一个处理多部分表单帖子的 servlet。该帖子实际上是由嵌入在页面中的 Flash 文件上传组件制作的。在某些浏览器中,Flash 生成的 POST 不包含 JSESSIONID,这使我无法在发布期间从会话中加载某些信息。

Flash 上传组件确实在一个特殊的表单字段中包含 cookie 和会话信息。使用这个表单域,我实际上可以检索 JSESSIONID 值。问题是,我不知道如何使用这个 JSESSIONID 值来手动加载那个特定的会话。

编辑 -基于 ChssPly76 的解决方案,我创建了以下HttpSessionListener实现:

    @Override
    public void sessionCreated(final HttpSessionEvent se) {
        final HttpSession session = se.getSession();
        final ServletContext context = session.getServletContext();
        context.setAttribute(session.getId(), session);
    }

    @Override
    public void sessionDestroyed(final HttpSessionEvent se) {
        final HttpSession session = se.getSession();
        final ServletContext context = session.getServletContext();
        context.removeAttribute(session.getId());
    }

它将所有会话添加到ServletContext作为由其唯一 ID 映射的属性。我可以在上下文中放置一个会话地图,但这似乎是多余的。请发表对此决定的任何想法。接下来,我将以下方法添加到我的 servlet 以通过 id 解析会话:

    private HttpSession getSession(final String sessionId) {
        final ServletContext context = getServletContext();
        final HttpSession session = (HttpSession) context.getAttribute(sessionId);
        return session;
    }
4

5 回答 5

28

没有通过 id 检索会话的 API。

但是,您可以做的是在您的 Web 应用程序中实现会话侦听器并手动维护由 id 键入的会话映射(会话 id 可通过session.getId()检索)。然后,您将能够检索您想要的任何会话(而不是像其他人建议的那样欺骗容器用它替换您当前的会话)

于 2009-09-30T17:42:50.353 回答
3

一种安全的方法是在 cookie 中设置 jsession id - 这比在 url 中设置要安全得多。

将其设置为 cookie 后,您可以使用正常方式检索会话

request.getSession();

method.setRequestHeader("Cookie", "JSESSIONID=88640D6279B80F3E34B9A529D9494E09");
于 2015-01-20T19:27:11.843 回答
3

如果你使用的是Tomcat,你直接问tomcat(但它很难看)。我敢打赌,其他 Web 服务器还有其他 hacky 解决方案。

它使用“Manager”接口的一个实例来管理会话。让它丑陋的是我还没有找到一个很好的公共接口可以挂钩,所以我们必须使用反射来获取管理器。

下面是一个上下文监听器,它在上下文启动时抓取该管理器,然后可用于获取 Tomcat 会话。

public class SessionManagerShim implements ServletContextListener {
    static Manager manager;

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        try {
            manager = getManagerFromServletContextEvent(sce);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        manager = null;
    }

    private static Manager getManagerFromServletContextEvent(ServletContextEvent sce) throws NoSuchFieldException, IllegalAccessException {
        // Step one - get the ApplicationContextFacade (Tomcat loves facades)
        ApplicationContextFacade contextFacade = (ApplicationContextFacade)sce.getSource();

        // Step two - get the ApplicationContext the facade wraps
        Field appContextField = ApplicationContextFacade.class.getDeclaredField("context");
        appContextField.setAccessible(true);
        ApplicationContext applicationContext = (ApplicationContext)
                appContextField.get(contextFacade);

        // Step three - get the Context (a tomcat context class) from the facade
        Field contextField = ApplicationContext.class.getDeclaredField("context");
        contextField.setAccessible(true);
        Context context = (Context) contextField.get(applicationContext);

        // Step four - get the Manager. This is the class Tomcat uses to manage sessions
        return context.getManager();
    }

    public static Session getSession(String sessionID) throws IOException {
        return manager.findSession(sessionID);
    }
}

您可以将其添加为 web.xml 中的侦听器,它应该可以工作。

然后你可以这样做来获得一个会话。

于 2018-02-05T18:20:51.750 回答
1

servlet 规范中没有办法,但您可以尝试:

  • 在 Flash 发出的请求中手动设置 cookie

  • 或者按照 Taylor L 的建议进行操作,因为我正在键入并将 jsessionid 参数添加到 URI 的路径中。

这两种方法都会将您的应用程序绑定到在行为类似于 Tomcat 的 servlet 容器上运行;我想他们中的大多数人都这样做。两者都需要您的 Flash 小程序向页面询问其 cookie,这可能会强加 JavaScript 依赖性。

于 2009-09-30T17:40:23.057 回答
0

这是一个非常好的帖子。我看到使用会话侦听器不断向上下文添加会话的一个潜在问题是,根据您拥有的并发会话数量,它可能会变得非常胖。然后是为侦听器配置 Web 服务器的所有额外工作。

那么如何获得一个更简单的解决方案。我确实实现了这一点,并且效果很好。因此,在加载 flash 上传对象的页面上,将 session 和 sessionid 作为键值对存储在 application 对象中,然后将该 session id 作为 post 参数传递给上传页面。在上传页面上,查看该 sessionid 是否已经在应用程序中,因此使用该会话,否则,从请求中获取一个。此外,然后继续从应用程序中删除该密钥以保持一切清洁。

在 swf 页面上:

application.setAttribute(session.getId(), session);

然后在上传页面:

String sessid = request.getAttribute("JSESSIONID");
HttpSession sess = application.getAttribute(sessid) == null ?
        request.getSession() :
        (HttpSession)application.getAttribute(sessid);
application.removeAttribute(sessid);

非常好的解决方案。谢谢你。

于 2012-08-12T00:21:32.927 回答