Почему getSession () не возвращает один и тот же сеанс в последующих запросах, удаленных за короткие промежутки времени?
Я посылаю $.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
сессия.getId (): 9212B14094AB92D0F7F10EE21F593E52
request2:
isSessionNew: true
cookieFromRequestHeader: JSESSIONID=FD0D502635EEB67E3D36203E26CBB59A
сессия.getId (): E8734E413FA3D3FEBD4E38A7BF27BA58
как вы можете видеть, сервер явно создал новый сеанс для 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:false
cookieFromRequestHeader: JSESSIONID=E8734E413FA3D3FEBD4E38A7BF27BA58 сессия.getId (): E8734E413FA3D3FEBD4E38A7BF27BA58
request2':
isSessionNew:false
cookieFromRequestHeader: JSESSIONID=E8734E413FA3D3FEBD4E38A7BF27BA58
сессия.getId (): E8734E413FA3D3FEBD4E38A7BF27BA58
если вы видите близко сейчас, идентификатор сеанса тот же (в request1' и request2') и является последним созданным из запроса 2. Есть ли способ получить один и тот же сеанс из нескольких последующих запросов, которые поступают на сервер в очень короткие сроки?
Я не использую никаких специальных функций - я использую стратегию Spring out of the box session. Кроме того, похоже, что cookie JSESSIONID из запросов frist 2 (request1 и request2) приходят с первого раза, когда я посещаю страницу (скажем, был request0 отправлен на сервер, когда он создал этот JSESSIONID). Но это также похоже, если вы явно не вызываете request.getSession (), бэкэнд/сервер всегда будет создавать новый JSESSIONID для каждого ответа и отправлять его обратно клиенту. Поэтому, когда новый запрос отправляется от клиента после получения ответа, у него будет новый JSESSIONID. Похоже, что Spring out of the box обработка сеанса не работает должным образом.
С Уважением,
деспот!--11-->
ДОПОЛНИТЕЛЬНЫЕ ИССЛЕДОВАНИЯ:
Я хотел чтобы узнать, могу ли я зарегистрировать создание сеанса с помощью HttpSessionListner. Таким образом, я вижу, когда создается сеанс с идентификатором FD0D502635EEB67E3D36203E26CBB59A (cookie, который отправляется в request1 и request2). Кроме того, погода с помощью прослушивателя (SessionProcessor) я могу хранить сеансы на карте по идентификатору, а затем извлекать их по идентификатору из файла cookie (поэтому мне не нужно создавать другой сеанс).
Итак, вот код:
public interface ISessionProcessor extends ISessionRetriever, ISessionPopulator {
}
public interface ISessionRetriever {
HttpSession getSession(String sessionId);
}
public interface ISessionPopulator {
HttpSession setSession(String sessionId, HttpSession session);
}
причина разделение их было связано с тем, что я хотел только позволить слушателю добавлять сеансы на карту, а контроллеры-только создавать сеанс через запрос.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});
}
}
в интернете.XML: орг.springframework.сеть.контекст.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-контексте.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()});
}
}
это дало мне те же результаты. Оказалось, что сессии создание посредством запроса.getSession (когда spring сам из коробки создал сеанс), либо не был зарегистрирован слушателем, либо cookie/jsessionID пришел откуда-то еще. Ищите ответ для большего.
другое источник это помогло мне пройти через проблемы HttpSession:
впрыска контекста сервлета в контроллер
обзор параллелизма при работе с HttpSession
использование объекта HttpSession для синхронизации (избегайте этого)
"лучший" способ сделать синхронизацию при работе с HttpSession
некоторые весенние справочные материалы:
управление сеансами
управление сеансами в безопасности!--84-->
дискуссии о том, как получить сеанс, когда у вас есть код (что я сделал выше):
обсуждение coderanch
stackoverflow
сообщение, которое помогло мне завершить мой слушатель autowiring
3 ответов
похоже, что cookie JSESSIONID из запросов frist 2 (request1 и request2) приходят с первого раза, когда я посещаю страницу (допустим, был отправлен request0 на сервер, когда он создал это JSESSIONID).
Это было не так. У меня есть 2 приложения, развернутые в одном домене на одном сервере. Поэтому, когда я звонил http://mydomain.com/app1/initpage сервер создал сеанс для app1 с идентификатором FD0D502635EEB67E3D36203E26CBB59A и отправил этот JSESSIONID в cookie клиенту. Клиент сохранил файл cookie под mydomain.com и во второй раз, когда я казнил http://mydomain.com/app2/executeService, браузер клиента отправил JSESSIONID из файла cookie в заголовке запроса. Я получил его на сервере, но это не был сеанс в другом app2.
это объясняет тот факт, что когда я отправляю два других запроса (request1' и request2'), у них есть sessionID, созданный в соответствующем приложении.
посмотреть подробнее здесь:
развертывание нескольких веб-приложений на одном сервере
при каких условиях создается JSESSIONID?
что касается конкретного ответа на мой вопрос, похоже, что вам нужно синхронизировать 1-й запрос, чтобы вы всегда были уверены, что у вас есть тот же идентификатор сеанса в следующих запросах. Следующие запросы после 1-го, могут быть однако асинхронный.
просто сохраните файл cookie (с JESSIONID) в клиенте , когда вы отправляете последующий запрос на сервер , поместите сохраненный файл cookie в поле заголовка запроса и отправьте, затем вы получите тот же сеанс в конце сервера.
клиент (IOS) сохраните файл cookie из ответа:
NSHTTPURLResponse* httpURLReqponse = (NSHTTPURLResponse*) response;
NSDictionary* allHeaders = [httpURLReqponse allHeaderFields];
NSLog(@"Response Headers : %@ ", allHeaders);
NSString* cookie = [allHeaders objectForKey: @"Set-Cookie"];
DATA.cookies = cookie; // Store the cookie
клиент (IOS) Отправьте свой последующий запрос с помощью cookie:
// Put the stored cookie in your request header
[(NSMutableURLRequest*)request addValue: DATA.cookies forHTTPHeaderField:@"cookie"];
[NSURLConnection sendAsynchronousRequest: request queue:[NSOperationQueue mainQueue] completionHandler:nil];
не только для клиента IOS . Затем, в конце сервера , вы получите то же самое сеанс:
сервер (JavaEE) получить HttpSession:
// Get the session, print its hashCode. You will find out that it's same as previous.
HttpSession session = ServletActionContext.getRequest().getSession();
Я заметил, что это происходит, когда cookies отключены в :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="">
<context-root>/some-app</context-root>
<class-loader delegate="true"/>
<jsp-config>
<property name="keepgenerated" value="true">
<description>Keep a copy of the generated servlet class' java code.</description>
</property>
</jsp-config>
<session-config>
<session-properties>
<property name="timeoutSeconds" value="600"/>
<property name="enableCookies" value="false"/>
</session-properties>
</session-config>
</glassfish-web-app>
Он должен быть!--2--> для сохранения идентификатора сеанса из того же соединения.