Я отправляю запрос $.getJSON
(HTTP GET) дважды (с разными данными) один за другим (скажем, у нас есть запрос1 и request2). В инструментах разработчика из FF и Chrome я вижу, что у меня такое же поле заголовка cookie:JSESSIONID=FD0D502635EEB67E3D36203E26CBB59A
.
На стороне сервера я пытаюсь получить сеанс:
HttpSession session = request.getSession();
boolean isSessionNew = session.isNew();
String sessionId = session.getId();
String cookieFromRequestHeader = request.getHeader("cookie");
Если я напечатаю эти переменные для обоих запросов, я получаю,
request1:
isSessionNew: верно
cookieFromRequestHeader: JSESSIONID = FD0D502635EEB67E3D36203E26CBB59A
session.getId(): 9212B14094AB92D0F7F10EE21F593E52
request2:
isSessionNew: верно
cookieFromRequestHeader: JSESSIONID = FD0D502635EEB67E3D36203E26CBB59A
session.getId(): E8734E413FA3D3FEBD4E38A7BF27BA58
Как вы можете видеть, сервер четко создал новый сеанс для запроса2 на 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), я получаю,
request1 ':
isSessionNew: ложь
cookieFromRequestHeader: JSESSIONID = E8734E413FA3D3FEBD4E38A7BF27BA58 session.getId(): E8734E413FA3D3FEBD4E38A7BF27BA58
request2 ':
isSessionNew: ложь
cookieFromRequestHeader: JSESSIONID = E8734E413FA3D3FEBD4E38A7BF27BA58
session.getId(): E8734E413FA3D3FEBD4E38A7BF27BA58
Если вы сейчас видите, идентификатор сеанса один и тот же (в request1 'и request2') и является последним, созданным из запроса2. Есть ли способ получить один и тот же сеанс из нескольких последующих запросов, поступающих на сервер за очень короткие временные рамки?
Я не использую никаких специальных функций - я использую Spring из стратегии сеанса. Кроме того, похоже, что cookie JSESSIONID из запросов frist 2 (request1 и request2) поступает с первого раза, когда я посещаю страницу (скажем, что был отправлен запрос0 на сервер, когда он создал этот JSESSIONID). Но это также выглядит, если вы явно не вызываете request.getSession(), сервер/сервер всегда будет создавать новый JSESSIONID для каждого ответа и отправлять его клиенту. Поэтому, когда новый запрос отправляется от клиента после ответа, он будет иметь новый JSESSIONID. Похоже, что Spring обработка сеанса не работает должным образом.
С уважением,
деспот
ДОПОЛНИТЕЛЬНЫЕ ИССЛЕДОВАНИЯ:
Я хотел посмотреть, могу ли я зарегистрировать создание сеанса с помощью HttpSessionListner. Таким образом, я вижу, когда создается сеанс с идентификатором FD0D502635EEB67E3D36203E26CBB59A (файл cookie, отправляемый в request1 и request2). Кроме того, погода, использующая прослушиватель (SessionProcessor), я могу хранить сеансы на карте по id, а затем извлекать их по id из файла cookie (так что мне не нужно создавать другой сеанс).
Итак, вот код:
public interface ISessionProcessor extends ISessionRetriever, ISessionPopulator {
}
public interface ISessionRetriever {
HttpSession getSession(String sessionId);
}
public interface ISessionPopulator {
HttpSession setSession(String sessionId, HttpSession session);
}
Причина их разделения заключалась в том, что я только хотел, чтобы слушатель добавлял сеансы на карту, а контроллеры только для того, чтобы иметь возможность создавать сеанс через request.getSession(), поэтому всегда вызывался метод sessionSreated listner (как вы увидите ниже).
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 пришел откуда-то еще. Посмотрите ответ для большего.
Другие источники , которые помогли мне преодолеть проблемы HttpSession:
инъекция контекста сервлетов в контроллере
обзор concurrency, когда вам нужно работать с HttpSession
используя объект HttpSession для синхронизации (избегайте этого)
"лучший" способ выполнить синхронизацию при работе с HttpSession
некоторые Spring справочные материалы:
управление сеансом
управление сеансом в безопасности
дискуссии о том, как получить сеанс, когда у вас есть sessionId (что я сделал выше):
обсуждение coderanch
qaru.site/info/204462/...
сообщение, которое помогло мне завершить мой аутсорсинг слушателя