且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在Google App Engine Java应用程序上的模块之间共享会话?

更新时间:2023-11-19 20:54:22

您可以实现HttpServletFilter和HttpSessionListener的组合,以同时处理两个webapps。当请求修改会话状态时,将其保存到持久性存储(db)中,并且对于每个请求,检查会话对象是否与db保持最新。



注意这需要两个Web应用程序在相同的域下(例如:mydomain.com/webapp1和mydomain.com/webapp2)提供服务。否则,JSESSIONID cookie将不会被浏览器交付。



现在有一种现成的解决方案,例如 Hazelcast 。它是专为负载平衡/故障转移而设计的,但您可能可以将其用于预期目的。



另外考虑使用HttpSession的可能性是错误的架构设计。也许你应该用数据库/ API进行交易?


When I store something in the session via HttpSession in module A:

HttpSession session = req.getSession(true);
session.setAttribute("username", "Eng.Fouad");

then I try to retrieve this information from within module B (during the same browser session):

HttpSession session = req.getSession(true);
String username = session.getAttribute("username"); // null!

I got null as a value, which means different session.

How to share session across multiple modules in GAE?


Old Answer which I think it doesn't work well:

I've been trying to solving this issue for weeks. It turns out that the modules don't share sessions because the cookies are different across different sub-domains (module1.apphost.com cookies != module2.apphost.com cookies). To solve it, simply set cookies domain in web.xml of each module:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         id="WebApp_ID" version="2.5">

  <context-param>
    <param-name>org.mortbay.jetty.servlet.SessionDomain</param-name>
    <param-value>.apphost.com</param-value>
  </context-param>
  <context-param>
    <param-name>org.mortbay.jetty.servlet.SessionPath</param-name>
    <param-value>/</param-value>
  </context-param>
  <context-param>
    <param-name>org.mortbay.jetty.servlet.SessionURL</param-name>
    <param-value>none</param-value>
  </context-param>

  ...

</web-app>


EXTRA:

Here is a list of all init parameters you can use with Jetty cookies:


EDIT: Workaround for development environment:

  1. Make the port of each module fixed (using JVM arg -Dcom.google.appengine.devappserver_module.{module_name}.port=8081). For example, module1 is always hosted at localhost:8888, and module2 is always hosted at localhost:8889. See this answer.
  2. Bind the localhost with the port of each module to a custom domain using Fiddler. For example, moule1.gaelocal.com points to localhost:8888 and moule2.gaelocal.com points to localhost:8889. See this answer.
  3. Update web.xml of each module and replace .apphost.com with .gaelocal.com (or just use .apphost.com for both environment).

You can implement a combination of HttpServletFilter and HttpSessionListener that synchronizes accross both webapps. When a request modifies session state, save it to a persistent store (db), and for each requests, checks if the session objects are up to date with db.

Note that this require both web app to be served under the same domain (eg: mydomain.com/webapp1 and mydomain.com/webapp2). Otherwise the JSESSIONID cookie wouldn't be delivered by the browser.

There's an off the shelf solution that does this such as Hazelcast. It's designed for load balancing / failover but you might be able to use it for the intended purpose.

Also consider the possibility using HttpSession is a wrong architectural design. Maybe you should be transacting with a database / API instead?