2012-10-22 2 views
13

Ich sende eine $.getJSON (HTTP GET) Anfrage zweimal (mit verschiedenen Daten), eine nach der anderen (sagen wir, wir haben Anfrage1 und Anfrage2). Ich kann in den Entwicklern von FF und Chrome sehen, dass ich das gleiche cookie:JSESSIONID=FD0D502635EEB67E3D36203E26CBB59A Header-Feld habe.Warum wird getSession() nicht die gleiche Sitzung in nachfolgenden Anfragen in kurzen Zeiträumen distanziert zurückgegeben?

Auf der Serverseite Ich versuche, um die Sitzung zu bekommen:

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

Wenn ich diese Variablen für beide Anfragen drucke ich bekommen,
Anfrage1:

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

request2:

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

Wie Sie sehen können, wird der Server eindeutig eine neue Sitzung erstellt für request2 auf einem request.getSession(). Aber warum macht es das? Es sollte theoretisch synchronisiert werden und Ihnen die gleiche Sitzung geben, die die erste Anfrage (die diesen Code zuerst erreichte) erstellt hat. nun sicher sein, dass die Sitzung Schöpfung synchronisiert habe ich folgendes:

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

und ich habe die gleichen Ergebnisse.

Wenn ich die gleichen Anfragen später wieder senden (lässt Anfrage1' sagen und request2 ') ich werde,
Anfrage1':

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

request2' :

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

Wenn Sie genau jetzt sehen, ist die Session-ID die gleiche (in Anfrage1' und request2') und ist der Letzte, der aus der Anfrage erstellt wurde2. Gibt es eine Möglichkeit, die gleiche Sitzung von mehreren nachfolgenden Anfragen zu bekommen, die in sehr kurzen Zeiträumen zum Server kommen?

Ich verwende keine speziellen Funktionen - ich verwende die Out of the Box-Session-Strategie von Spring.Es sieht auch so aus, als käme der Cookie JSESSIONID aus den ersten 2 Anfragen (request1 und request2) vom ersten Mal, wenn ich die Seite besuche (sagen wir mal, es wurde eine Anfrage0 an den Server gesendet, als er diese JSESSIONID erstellt hat). Es sieht aber auch so aus, dass Sie, wenn Sie request.getSession() nicht explizit aufrufen, das Backend/Server immer eine neue JSESSIONID für jede Antwort erstellen und diese an den Client zurücksenden wird. Wenn also eine neue Anfrage von dem Client gesendet wird, nachdem eine Antwort kommt, wird sie eine neue JSESSIONID haben. Es sieht so aus, als ob die Spring Session-Behandlung nicht richtig funktioniert.

Mit freundlichen Grüßen,
Despot

ZUSÄTZLICHE RESEARCH:

Ich wollte sehen, ob ich die Session-Erstellung mit einem HttpSessionListner registrieren. Auf diese Weise kann ich sehen, wenn die Sitzung mit der ID FD0D502635EEB67E3D36203E26CBB59A (der Cookie, der in Anforderung1 und Anforderung2 gesendet wird) erstellt wird. Und auch, Wetter mit dem Listener (der SessionProcessor) Ich kann die Sitzungen in einer Karte nach ID speichern und später durch die ID aus dem Cookie abrufen (so muss ich keine weitere Sitzung erstellen).
So, hier ist der Code:

public interface ISessionProcessor extends ISessionRetriever, ISessionPopulator { 
} 

public interface ISessionRetriever { 

    HttpSession getSession(String sessionId); 
} 

public interface ISessionPopulator { 

    HttpSession setSession(String sessionId, HttpSession session); 
} 

Der Grund für die Trennung davon war, weil ich nur die Zuhörer erlauben wollte Sitzungen der Karte hinzuzufügen, und die Controller nur eine Sitzung über Anfrage erstellen zu können. getSession() - also wurde die Methode sessionCreated des Listners immer aufgerufen (wie Sie sehen werden).

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}); 
    } 
} 

in 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> 

in my-Servlet-context.xml:

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

in meinem Controller :

    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()}); 
          } 
        } 

Dies gab mir die gleichen Ergebnisse. Es schien, dass die Sitzungserstellung mit anderen Mitteln als request.getSession (wenn Spring nicht in der Box die Sitzung erstellt hat) entweder vom Listener registriert wurde oder die cookie/jsessionID von woanders kam. Schauen Sie die Antwort für mehr an.

Andere Quellen, die mich durch die Http Fragen gehen geholfen:
servlet context injection in controller
overview of concurrency when you have to work with HttpSession
using HttpSession object to do synchronization (avoid this)
the "best" way to do synchronization when working with HttpSession
einige Frühjahr Referenz Zeug:
session management
session management in security
Diskussionen darüber, wie Sitzung zu bekommen wenn du eine sessionId hast (w Hut Ich habe oben):
coderanch discussion
stackoverflow
the post that helped me finalize my listener autowiring

Antwort

1

es wie das Cookie JSESSIONID von der frist 2 Anfragen (Anfrage1 und request2) stammen aus dem ersten Mal sieht ich die Seite besuchen (Lasset sagen, es wurde eine Anfrage0 an den Server gesendet, als es diese JSESSIONID) erstellt hat.

Dies war nicht wahr. Ich habe 2 Anwendungen unter derselben Domäne auf demselben Server bereitgestellt. Als ich also http://mydomain.com/app1/initpage anrief, erstellte der Server eine Sitzung für app1 mit der ID FD0D502635EEB67E3D36203E26CBB59A und schickte diese JSESSIONID in einem Cookie an den Client. Der Client hat den Cookie unter mydomain.com gespeichert und das zweite Mal, als ich http://mydomain.com/app2/executeService ausgeführt habe, hat der Client-Browser die JSESSIONID aus dem Cookie im Anforderungsheader gesendet. Ich habe es auf dem Server erhalten, aber das war keine Sitzung in der anderen App2.

Dies erklärt die Tatsache, dass, wenn ich die anderen zwei Anfragen (request1 'und request2') senden sie eine SessionID für die entsprechende Anwendung erstellt haben.

Werfen Sie einen Blick mehr hier:
Deploying multiple web apps in same server
Under what conditions is a JSESSIONID created?

Was die konkrete Antwort auf meine Frage, es scheint, dass Sie die erste Anforderung synchronisiert vornehmen müssen, so sind Sie immer sicher, dass Sie das haben gleiche Session ID in den folgenden Anfragen. Die folgenden Anfragen nach der ersten können jedoch asynchron sein.

0

Speichern Sie einfach Ihren Cookie (mit JESSIONID) im Client, wenn Sie eine nachfolgende Anfrage an den Server senden, den gespeicherten Cookie in Ihr Anfrage-Headerfeld setzen und senden, dann erhalten Sie die gleiche Sitzung am Serverende.

CLIENT (IOS) speichern Sie Ihre Cookie-Antwort:

NSHTTPURLResponse* httpURLReqponse = (NSHTTPURLResponse*) response; 
    NSDictionary* allHeaders = [httpURLReqponse allHeaderFields]; 
    NSLog(@"Response Headers : %@ ", allHeaders); 
    NSString* cookie = [allHeaders objectForKey: @"Set-Cookie"]; 
    DATA.cookies = cookie;  // Store the cookie 

CLIENT (IOS) mit Cookie Ihre spätere Anfrage senden:

// Put the stored cookie in your request header 
[(NSMutableURLRequest*)request addValue: DATA.cookies forHTTPHeaderField:@"cookie"]; 
[NSURLConnection sendAsynchronousRequest: request queue:[NSOperationQueue mainQueue] completionHandler:nil]; 

Nicht nur für IOS-Client.Dann wird in der Serverseite werden Sie die gleiche Sitzung erhalten:

Server (JavaEE) GET Http:

// Get the session, print its hashCode. You will find out that it's same as previous. 
HttpSession session = ServletActionContext.getRequest().getSession(); 
0

Ich bemerkte, dass es passiert, wenn Cookies deaktiviert sind in ...web.xml Datei:

<?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> 

Es sollte <property name="enableCookies" value="false"/> sein, Sitzungs-ID von derselben Verbindung beizubehalten.

Verwandte Themen