为什么 getSession() 在短时间内间隔的后续请求中不返回相同的会话?

2024-05-06

我正在发送一个$.getJSON(HTTP GET) 请求两次(使用不同的数据),一次又一次(假设我们有 request1 和 request2)。我可以在 FF 和 Chrome 的开发者工具中看到我有相同的cookie:JSESSIONID=FD0D502635EEB67E3D36203E26CBB59A标头字段。

在服务器端,我尝试获取会话:

HttpSession session = request.getSession();
boolean isSessionNew = session.isNew();
String sessionId = session.getId();
String cookieFromRequestHeader = request.getHeader("cookie");

如果我为收到的两个请求打印这些变量,
请求1:

isSessionNew:true
cookieFromRequestHeader:JSESSIONID=FD0D502635EEB67E3D36203E26CBB59A
session.getId():9212B14094AB92D0F7F10EE21F593E52

请求2:

isSessionNew:true
cookieFromRequestHeader:JSESSIONID=FD0D502635EEB67E3D36203E26CBB59A
session.getId(): E8734E413FA3D3FEBD4E38A7BF27BA58

正如您所看到的,服务器显然在 a 上为 request2 创建了一个新会话request.getSession()。但它为什么要这样做呢?理论上它应该是同步的,并为您提供与第一个请求(首先到达此代码)创建的相同会话。现在,为了确保会话创建同步,我执行了以下操作:

@Autowired
private ServletContext servletContext;
...
synchronized (servletContext) {
    HttpSession session = request.getSession();
    boolean isSessionNew = session.isNew();
    String sessionId = session.getId();
    String cookieFromRequestHeader = request.getHeader("cookie");
}

我得到了相同的结果。

如果我稍后再次发送相同的请求(假设 request1' 和 request2')我得到,
请求1':

isSessionNew:假
cookieFromRequestHeader:JSESSIONID=E8734E413FA3D3FEBD4E38A7BF27BA58 session.getId():E8734E413FA3D3FEBD4E38A7BF27BA58

请求2':

isSessionNew:假
cookieFromRequestHeader:JSESSIONID=E8734E413FA3D3FEBD4E38A7BF27BA58
session.getId():E8734E413FA3D3FEBD4E38A7BF27BA58

如果您现在仔细观察,会话 ID 是相同的(在 request1' 和 request2' 中),并且是从 request2 创建的最后一个。有没有办法让我从在很短的时间内到达服务器的多个后续请求中获取相同的会话?

我没有使用任何特殊功能 - 我正在使用 Spring 的开箱即用会话策略。另外,看起来前 2 个请求(request1 和 request2)中的 cookie JSESSIONID 来自我第一次访问该页面(假设在创建此 JSESSIONID 时有一个 request0 发送到服务器)。但看起来除非您显式调用 request.getSession(),否则后端/服务器将始终为每个响应创建一个新的 JSESSIONID 并将其发送回客户端。因此,当响应到来后从客户端发送新请求时,它将有一个新的 JSESSIONID。看起来 Spring 开箱即用的会话处理无法正常工作。

亲切的问候,
despot

额外的研究:

我想看看是否可以使用 HttpSessionListner 注册会话创建。这样我就可以看到 id 为 FD0D502635EEB67E3D36203E26CBB59A 的会话(在 request1 和 request2 中发送的 cookie)何时创建。而且,使用侦听器(SessionProcessor)的天气我可以通过 id 将会话存储在地图中,然后通过 cookie 中的 id 检索它们(因此我不需要创建另一个会话)。
所以这是代码:

public interface ISessionProcessor extends ISessionRetriever, ISessionPopulator {
}

public interface ISessionRetriever {

    HttpSession getSession(String sessionId);
}

public interface ISessionPopulator {

    HttpSession setSession(String sessionId, HttpSession session);
}

分开这些的原因是因为我只想允许侦听器将会话添加到地图,而控制器只能通过 request.getSession() 创建会话 - 因此侦听器的 sessionCreated 方法总是被调用(正如您下面会看到)。

public class SessionProcessor implements ISessionProcessor {

    private Map<String, HttpSession> sessions = new HashMap<String, HttpSession>();

    @Override
    public HttpSession getSession(String sessionId) {
            return sessions.get(sessionId);
    }

    @Override
    public HttpSession setSession(String sessionId, HttpSession session) {
            return sessions.put(sessionId, session);
    }

}

public class SessionRetrieverHttpSessionListener implements HttpSessionListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(SessionRetrieverHttpSessionListener.class);

    @Autowired
    private ISessionPopulator sessionPopulator;

    @Override
    public void sessionCreated(HttpSessionEvent se) {
            HttpSession session = se.getSession();
            LOGGER.debug("Session with id {} created. MaxInactiveInterval: {} session:{}", new Object[]{session.getId(), session.getMaxInactiveInterval(), session});
            sessionPopulator.setSession(session.getId(), session);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
            HttpSession session = se.getSession();
            // session has been invalidated and all session data (except Id) is no longer available
            LOGGER.debug("Session with id {} destroyed. MaxInactiveInterval: {}, LastAccessedTime: {}, session:{}", 
                            new Object[]{session.getId(), session.getMaxInactiveInterval(), session.getLastAccessedTime(), session});
    }
}  

在 web.xml 中: org.springframework.web.context.ContextLoaderListener

<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/my-servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<listener>
    <listener-class>mypackage.listener.SessionRetrieverHttpSessionListener</listener-class>
</listener>

<servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

在 my-servlet-context.xml 中:

<bean class="mypackage.listener.SessionProcessor"/>
<bean class="mypackage.SomeController"/>

在我的控制器中:

                    synchronized (servletContext) {
                            String cookieFromRequestHeader = request.getHeader("cookie");
                            LOG.debug("cookieFromRequestHeader:{}", new Object[] {cookieFromRequestHeader});
                            String jsessionIdFromCookieFromRequestHeader = cookieFromRequestHeader.substring(cookieFromRequestHeader.indexOf("=") + 1);
                            LOG.debug("jsessionIdFromCookieFromRequestHeader:{}", new Object[] {jsessionIdFromCookieFromRequestHeader});
                            session = sessionRetriever.getSession(jsessionIdFromCookieFromRequestHeader);
                            LOG.debug("session:{}", new Object[] {session});
                            if (session == null) {
                            LOG.debug("request.isRequestedSessionIdFromCookie():{}, request.isRequestedSessionIdFromURL():{}, WebUtils.getSessionId(request):{}.", new Object[] {request.isRequestedSessionIdFromCookie(), request.isRequestedSessionIdFromURL(), WebUtils.getSessionId(request)});
                            session = request.getSession();
                            boolean isSessionNew = session.isNew();
                            LOG.debug("Is session new? - {}. The session should not be new after the first fingerprint part is received - check if this occured in the logs - if that happend than there is an error!", isSessionNew);
                            LOG.debug("request.isRequestedSessionIdFromCookie():{}, request.isRequestedSessionIdFromURL():{}, WebUtils.getSessionId(request):{}.", new Object[] {request.isRequestedSessionIdFromCookie(), request.isRequestedSessionIdFromURL(), WebUtils.getSessionId(request)});
                            //read https://stackoverflow.com/a/2066883 and think about using ServletContextAware also.
                            LOG.debug("cookieFromRequestHeader:{} session.getId(): {}", new Object[]{cookieFromRequestHeader, session.getId()});
                            }
                    }

这给了我同样的结果。看来,通过 request.getSession 以外的方式创建会话(当 spring 本身开箱即用地创建会话时),要么没有由侦听器注册,要么 cookie/jsessionID 来自其他地方。查看答案以了解更多信息。

Other sources这帮助我解决了 HttpSession 问题:
控制器中的 servlet 上下文注入 https://stackoverflow.com/questions/2066843/get-web-app-root-from-spring-controller/2066883#2066883
必须使用 HttpSession 时的并发概述 http://www.ibm.com/developerworks/library/j-jtp09238/index.html
使用 HttpSession 对象进行同步(避免这种情况) https://stackoverflow.com/questions/1820629/using-request-getsession-as-a-locking-object
使用 HttpSession 时进行同步的“最佳”方法 https://stackoverflow.com/questions/9802165/is-synchronization-within-an-httpsession-feasible/9802428#9802428
一些春季参考资料:
会话管理 http://static.springsource.org/spring-security/site/docs/3.1.x/reference/session-mgmt.html
安全中的会话管理 http://static.springsource.org/spring-security/site/docs/3.1.x/reference/ns-config.html#Session%20Management
关于当你有 sessionId 时如何获取会话的讨论(我上面所做的):
代码牧场讨论 http://www.coderanch.com/t/365859/Servlets/java/session-object-session-ID
堆栈溢出 https://stackoverflow.com/questions/1499581/how-can-i-manually-load-a-java-session-using-a-jsessionid/1499625#1499625
帮助我完成侦听器自动装配的帖子 http://www.mkyong.com/spring/spring-how-to-do-dependency-injection-in-your-session-listener/


它看起来像来自前 2 个请求的 cookie JSESSIONID (request1 和 request2) 来自我第一次访问该页面 (假设当服务器创建这个时,有一个 request0 发送到服务器 JSESSIONID)。

这不是真的。我在同一台服务器上的同一域下部署了 2 个应用程序。所以当我打电话的时候http://mydomain.com/app1/initpage http://mydomain.com/app1/initpage服务器为 app1 创建了一个 id 为 FD0D502635EEB67E3D36203E26CBB59A 的会话,并将此 JSESSIONID 通过 cookie 发送给客户端。客户端将cookie保存在mydomain.com下以及我第二次执行时http://mydomain.com/app2/executeService http://mydomain.com/app2/executeService,客户端浏览器从请求标头中的 cookie 发送 JSESSIONID。我在服务器上收到了它,但这不是另一个应用程序2中的会话。

这解释了当我发送其他两个请求(请求 1' 和请求 2')时,它们在相应的应用程序上创建了一个会话 ID。

在这里查看更多内容:
在同一服务器上部署多个 Web 应用程序 https://stackoverflow.com/questions/220661/deploying-multiple-web-apps-in-same-server/220690#220690
JSESSIONID 在什么条件下创建? https://stackoverflow.com/questions/595872/under-what-conditions-is-a-jsessionid-created

至于我的问题的具体答案,看来您需要同步第一个请求,以便始终确保在以下请求中具有相同的会话 ID。不过,第一个请求之后的后续请求可以是异步的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 getSession() 在短时间内间隔的后续请求中不返回相同的会话? 的相关文章

  • 路径中 File.separator 和斜杠之间的区别

    使用有什么区别File separator和一个正常的 在 Java 路径字符串中 与双反斜杠相反 平台独立性似乎不是原因 因为两个版本都可以在 Windows 和 Unix 下运行 public class SlashTest Test
  • Mockito when().thenReturn 不必要地调用该方法

    我正在研究继承的代码 我编写了一个应该捕获 NullPointerException 的测试 因为它试图从 null 对象调用方法 Test expected NullPointerException class public void c
  • 防止 iOS 键盘在 cordova 3.5 中滚动页面

    我正在使用 Cordova 3 5 和 jQuery mobile 构建 iOS 应用程序 我在大部分应用程序中禁用了滚动功能 但是 当我选择输入字段时 iOS 键盘会打开并向上滚动页面 我不想要这个功能 由于输入足够高 键盘不会覆盖它 我
  • Java TestNG 与跨多个测试的数据驱动测试

    我正在电子商务平台中测试一系列商店 每个商店都有一系列属性 我正在考虑对其进行自动化测试 是否有可能有一个数据提供者在整个测试套件中提供数据 而不仅仅是 TestNG 中的测试 我尝试不使用 testNG xml 文件作为机制 因为这些属性
  • jQuery:处理 getJSON() 中的错误?

    使用 jQuery 时如何处理 500 错误getJSON http api jquery com jQuery getJSON 有几个关于错误处理的问题getJSON and https stackoverflow com questio
  • 使用 Jquery 清除 5 个空 TD

    我有一个正在填充的动态表 我知道我不应该这样做 但是你会如何连续找到 5 个空 TD 并隐藏它们呢 因此 如果行包含 5 个空 TD 则不显示 TD 我想删除每个实例 td td td td td td td td td td 在 DOM
  • 总是使用 Final?

    我读过 将某些东西做成最终的 然后在循环中使用它会带来更好的性能 但这对一切都有好处吗 我有很多地方没有循环 但我将 Final 添加到局部变量中 它会使速度变慢还是仍然很好 还有一些地方我有一个全局变量final 例如android Pa
  • 加密 JBoss 配置中的敏感信息

    JBoss 中的标准数据源配置要求数据库用户的用户名和密码位于 xxx ds xml 文件中 如果我将数据源定义为 c3p0 mbean 我会遇到同样的问题 是否有标准方法来加密用户和密码 保存密钥的好地方是什么 这当然也与 tomcat
  • Java Integer CompareTo() - 为什么使用比较与减法?

    我发现java lang Integer实施compareTo方法如下 public int compareTo Integer anotherInteger int thisVal this value int anotherVal an
  • 检查 jQuery 1.7 中是否存在基于文本的选择选项

    所以我有以下 HTML 片段
  • Jquery一键提交多个同名表单

    我有动态创建的循环表单 我需要一键提交所有表单 我正在遵循下面的代码 你能建议我怎么做吗 谢谢
  • 玩!框架:运行“h2-browser”可以运行,但网页不可用

    当我运行命令时activator h2 browser它会使用以下 url 打开浏览器 192 168 1 17 8082 但我得到 使用 Chrome 此网页无法使用 奇怪的是它以前确实有效 从那时起我唯一改变的是JAVA OPTS以启用
  • 声明的包“”与预期的包不匹配

    我可以编译并运行我的代码 但 VSCode 中始终显示错误 早些时候有一个弹出窗口 我不记得是什么了 我点击了 全局应用 从那以后一直是这样 Output is there but so is the error The declared
  • 编译器抱怨“缺少返回语句”,即使不可能达到缺少返回语句的条件

    在下面的方法中 编译器抱怨缺少退货声明即使该方法只有一条路径 并且它包含一个return陈述 抑制错误需要另一个return陈述 public int foo if true return 5 鉴于Java编译器可以识别无限循环 https
  • 在 JavaScript 循环之外声明变量可以提高速度和内存?

    C 也有类似的问题 但我们没有看到 JavaScript 的任何问题 在循环内声明变量是否可以接受 假设循环有 200 次迭代 使用样本 2 相对于样本 1 是否有性能要求 内存和速度 我们使用 jQuery 来循环 它提高了我们将 var
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • 捕获的图像分辨率太大

    我在做什么 我允许用户捕获图像 将其存储到 SD 卡中并上传到服务器 但捕获图像的分辨率为宽度 4608 像素和高度 2592 像素 现在我想要什么 如何在不影响质量的情况下获得小分辨率图像 例如我可以获取或设置捕获的图像分辨率为原始图像分
  • JGit 检查分支是否已签出

    我正在使用 JGit 开发一个项目 我设法删除了一个分支 但我还想检查该分支是否已签出 我发现了一个变量CheckoutCommand但它是私有的 private boolean isCheckoutIndex return startCo
  • 如何修复 JNLP 应用程序中的“缺少代码库、权限和应用程序名称清单属性”?

    随着最近的 Java 更新 许多人都遇到了缺少 Java Web Start 应用程序的问题Codebase Permissions and Application name体现属性 尽管有资源可以帮助您完成此任务 但我找不到任何资源综合的
  • 按日期对 RecyclerView 进行排序

    我正在尝试按日期对 RecyclerView 进行排序 但我尝试了太多的事情 我不知道现在该尝试什么 问题就出在这条线上适配器 notifyDataSetChanged 因为如果我不放 不会显示错误 但也不会更新 recyclerview

随机推荐

  • 单机Octave并行计算——包和示例

    我想在单台机器 而不是集群 上并行化 Octave 中的 for 循环 前段时间我问了一个关于Octave并行版本的问题Octave并行计算 https stackoverflow com questions 7047840 paralle
  • 可以使用多个数据库连接

    tSQLt 世界的新手 很棒的工具集 在我正在为其设置测试的存储过程中遇到了一个小问题 如果由于某种原因我有一个连接到多个数据库甚至多个 SQL 服务器 链接服务器 的存储过程 在这种情况下是否可以使用 tSQLt 进行单元测试 我已经评论
  • PHPQuery WebBrowser 插件 - 使用 cookies

    我正在尝试使用 PHPQuery 的 WebBrowser 插件登录网站 我能够成功登录 但我不确定如何重用上一次调用中的 cookie 到下一次调用 client phpQuery browserGet https website com
  • 能够存储微秒的 Date 对象

    我正在寻找一个能够存储到微秒粒度的 Date 对象 有人知道吗 标准Date对象仅存储到毫秒 我知道这是平台限制 我可以通过包装来解决这个问题Date加上自定义类别中的小数数量 然而 我希望避免编写一个带有适当计算等的内容 我需要解析一个b
  • Mysql Workbench 无法选择外键

    首先 我检查了很多问题并用谷歌搜索了很多 但没有一个解决我的问题 我正在使用 Mysql Workbench 6 3 创建表 我仅使用 gui 而不是单个查询来创建它们 之后我尝试创建一些外键int 11 列 但 GUI 不允许我这样做 这
  • 如何最高效地更新MongoDB中的大量文档?

    我想要最有效地更新大量 gt 100 000 文档 我的第一个天真的方法是在 JS 级别上进行 编写脚本 首先获取 ids 然后循环 ids 并通过 id 调用更新 完整 文档或 set 补丁 我遇到了内存问题 还将数据分成了最大块 500
  • Pandas 数据框列总和并收集结果

    给定以下数据框 import pandas as pd p1 name willy age 11 interest Lego p2 name willy age 11 interest games p3 name zoe age 9 int
  • 如何使用 swift 从 core-grapics API 获取窗口列表

    我正在尝试使用 Swift 从核心图形 API 获取 OSX 上的窗口列表 以便稍后捕获它们的图像 经过一番研究 我发现 CGWindowListCopyWindowInfo Objective C API 调用具有以下签名 CFArray
  • codecvt 不是 std 标头吗?

    此代码使用 Visual C 11 进行编译 并在 Windows 7 上按预期运行 但无法使用 Windows 7 上的 MinGW 4 7 0 或 Linux 上的 gcc 4 8 0 进行编译 编译用 std c 11 flag in
  • Android 中识别点击的图像区域?

    有没有办法在 Android 应用程序中确定用户单击了 ImageView 的哪个区域 例如 x y 坐标 谢谢 查看运动事件 http developer android com intl de reference android vie
  • 变基后无法推送到分支

    我们使用 git 并有一个 master 分支和开发人员分支 我需要添加一个新功能 然后将提交重新设置为 master 然后将 master 推送到 CI 服务器 问题是 如果我在变基期间发生冲突 我无法在变基完成后推送到我的远程开发人员分
  • 使用 SearchView 后重置操作栏

    我在用着SearchView小部件以在我的应用程序中启用搜索 首次单击搜索图标后 SearchView小部件会扩展到搜索字段 并且应用程序图标旁边会显示 后退 箭头 如果我单击应用程序图标 操作栏将恢复到初始状态 没有 后退 箭头 并且Se
  • 如何在 R 中使用相对路径从 mac 上的目录读取数据?

    我正在编写需要同时适用于 Mac 和 Windows 用户的代码 所有用户的计算机上都有 google 驱动器目录的本地副本 我有一段代码可以自动将工作目录设置为源文件位置 我们将此目录称为 directory1 在directory1 中
  • 用户输入时的空闲时间

    我遇到的问题是一个搜索函数 它应该调用我的doSearch 用户在我的系统中停止输入至少 100 毫秒后的方法 input q field 我试图通过使用这个逻辑来实现这一点answer https stackoverflow com a
  • 检测“文件下载”弹出窗口何时关闭

    我有一个网页 用 JSF 制作 其中一些链接允许用户获取 PDF 文件 当用户点击这样的链接时 会显示一个等待弹出窗口 它是一个模式面板 因为 PDF 的生成可能很长 并且一旦创建文件 IE 就会显示 文件下载 弹出窗口 建议 打开 保存
  • 从 GetLastError() 函数返回的错误代码中获取文本

    我需要获取从 GetLastError 函数获得的错误代码的文本 我看到了一些示例 但我想要一个获取代码并返回字符串的函数 谢谢大家 我猜你想要这样的东西 DWORD dwLastError GetLastError TCHAR lpBuf
  • RxJava - 链接请求和更新 UI

    我遇到的问题是这样的 我需要向服务器执行几个请求 下一个请求取决于前一个请求的结果 它们看起来像这样 缩写 Observable
  • 如何调试(最好在 IDE 中)MSBuild 脚本?

    我们非常广泛地使用 MSBuild 作为我们持续集成过程的一部分 虽然它非常强大 我们几乎可以在其中完成所有构建 测试和部署 利用一些自定义任务 我们发现使用标签对其进行调试是一种痛苦 并且不能总是为我们提供足够的信息 我发现 http w
  • 调用事件,h(args) 与 EventName?.Invoke()

    我总是这样调用事件 void onSomeEvent string someArg var h this EventName if h null h this new MyEventArgs someArg 今天 VS 2015 告诉我这可
  • 为什么 getSession() 在短时间内间隔的后续请求中不返回相同的会话?

    我正在发送一个 getJSON HTTP GET 请求两次 使用不同的数据 一次又一次 假设我们有 request1 和 request2 我可以在 FF 和 Chrome 的开发者工具中看到我有相同的cookie JSESSIONID F