【问题标题】:Google App Engine session loses attributeGoogle App Engine 会话丢失属性
【发布时间】:2018-12-03 12:41:07
【问题描述】:

我有一个存储会话授权详细信息的应用程序已经运行了多年,现在会话属性返回 null。我在每个请求开始时检索会话数据,并在返回响应之前设置它。该应用程序是在 GAE 标准上运行的 Spring 3 MVC。

会话已启用,<sessions-enabled>true</sessions-enabled>。我所有的对象都实现了可序列化。 更新 - 在检查项目历史时,我最近升级到 Java 8。我恢复到 Java 7,会话在设置后仍然返回 null 属性。设置回 Java 8。

protected void setSessionAccess(HttpServletRequest request, Access access) {
    logger.info("setting session access...");
    request.getSession().setAttribute(ACCESS, access);
}

protected Access getSessionAccess(HttpServletRequest request) {
    logger.info("getting session access...");
    Access access = (Access) request.getSession().getAttribute(ACCESS);
    if (access == null) {
        logger.log(Level.WARNING, "access is null, initializing access...");
        access = new Access();
    }
    return access;
}

在进行故障排除时,我添加了<async-session-persistence enabled="true" />,并将其删除,因为会话数据也用于导航目的。

更新 - 用户报告他们能够与某些浏览器/平台而不是其他浏览器/平台保持会话,这让我相信这与 cookie 有关。当我禁用会话 cookie 时,我可以重复该问题。 URL 重写会解决这个问题,但是为什么会突然中断呢?

非常感谢任何帮助!

【问题讨论】:

  • 我认为您的应用程序突然停止工作而您没有对其进行任何更改,这很奇怪。我唯一想到的是,App Engine 的内部虚拟机或库经历了重大变化,破坏了应用程序的正常功能。您是否查看过 release notes 以了解它们是否相关?
  • 我尝试了很多方法并且变得绝望,这已经持续了一周。从字面上看,恢复操作的唯一内容是删除数据存储区中的 _ah_SESSION 实体。我已准备好使用相同的代码部署一个新应用程序,以查看应用程序设置和配置中是否存在某些内容。我的用户会很高兴知道现在可以使用应用程序 。通过几次迭代,该应用程序大约有 5 年的历史。很快就会转向 RESTful 服务,也许还有 Docker 和 CI,干杯!如果这个应用程序再次出现问题,我会很痛苦。
  • 我希望这能修复它,祝你好运!如果这太棘手了,您可以随时联系官方支持
  • 我有一些用户仍然抱怨失去他们的身份验证,我和另一个人的工作正常,但日志显示一些会话属性丢失。我认为谷歌已经将他们的产品组转移到了 StackOverflow。我从未直接联系过 Google 寻求支持,但我可能需要调查一下。
  • 确实是这样,我是支持GCP的。然而,并非所有问题都可以在 SO 中得到解答,因为许多问题确实需要对代码、使用的实例/配置、日志等进行更深入的分析,而这些在 Stackoverflow 中是看不到的。如果它仍在继续,如果您有支持计划,您可能需要在 Support Center 内开票。或者,您可以使用public issue tracker

标签: java google-app-engine


【解决方案1】:

在我使用 Python/Flask 开发时可能不相关,但由于我错误地将应用程序“密钥”设置为在每个实例上随机生成的东西,我失去了会话。这意味着当用户从一个实例转移到另一个实例时,会话无法被访问,因为每个实例都有不同的密钥来签署 cookie/会话。

【讨论】:

  • 非常感谢,你救了我一整天。
【解决方案2】:

我按照Ggrimaldo 的建议使用public issue tracker 提交了请求。

他们确认这很可能是与浏览器相关的问题,因为某些浏览器和平台不会丢失会话。他们建议设置一个带有会话 ID 的 cookie,如果会话数据为空,则读取会话 ID。我发现这个post描述了如何从数据存储中读取_ah_session数据,并以这种方式实现,

try {
    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
    Key sessionKey = KeyFactory.createKey("_ah_SESSION", "_ahs" + sessionId);
    Entity sessionEntity = datastore.get(sessionKey);
    Blob blob = (Blob) sessionEntity.getProperty(_VALUES);
    byte[] sessionBytes = blob.getBytes();

    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(sessionBytes);
    ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
    return (Map<String, Object>) objectInputStream.readObject();
} catch (EntityNotFoundException e) {   
    logger.log(Level.INFO, e.getMessage());
} catch (Exception e) {
    logger.log(Level.SEVERE, e.getMessage(), e);
}

从这里调用,

String mySessionId = null;
for (Cookie cookie : cookies) {
    if ("MYSESSIONID".equals(cookie.getName())) {
        mySessionId = cookie.getValue();
    }
}
// returning code is above
sessionMap = gcpSessionService.getGcpSession(swgcSessionId);
if (sessionMap != null) {
    access = (Access) sessionMap.get(ACCESS);
}

我会要求我的用户重试并查看一下日志。这是一个特别烦人的问题,但由于我以俱乐部志愿者的身份维护该站点,因此没有任何人想要进行维护的投诉。我会发布更新。如果 jsessionid 不稳定,我将不得不求助于创建自己的 cookie (argh)。

所以,啊,这是我的 cookie 设置代码,从 stackoverflow 的其他地方复制而来,

protected void setMySessionCookie(HttpServletResponse response, String jSessionId) {

    logger.log(Level.INFO, "setting MYSESSIONID = " + jSessionId);

    final String cookieName = "MYSESSIONID";
    // you could assign it some encoded value
    final String cookieValue = jSessionId; 
    // TODO enforce SSL
    final Boolean useSecureCookie = false; 
    final int expiryTime = -1; // 24h in seconds
    final String cookiePath = "/";

    Cookie cookie = new Cookie(cookieName, cookieValue);
    // determines whether the cookie should only be sent using a secure protocol, such as HTTPS or SSL
    cookie.setSecure(useSecureCookie);
    // A negative value means that the cookie is not stored persistently and will be deleted when the Web browser exits. A zero value causes the cookie to be deleted.
    cookie.setMaxAge(expiryTime);
    // The cookie is visible to all the pages in the directory you specify, and all the pages in that directory's subdirectories
    cookie.setPath(cookiePath);

    response.addCookie(cookie);
}

我在首次建立会话时设置它,并在每次保存会话时更新它。每次将会话属性保存在会话中时,都有一些额外的条件逻辑用于设置或更新 cookie 中的会话值。它工作正常,我的用户很高兴。

首先没有明显的原因导致这种情况发生,所以希望没有人会遇到它。如果你愿意,请投票或发表评论,以便我知道是否只有我一个人,谢谢!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-14
    • 2013-06-26
    相关资源
    最近更新 更多