2012-10-22 17 views
13

Tôi gửi yêu cầu $.getJSON (HTTP GET) hai lần (với dữ liệu khác nhau), cái khác (cho phép chúng tôi có request1 và request2). Tôi có thể thấy trong các công cụ phát triển từ FF và Chrome mà tôi có cùng trường tiêu đề cookie:JSESSIONID=FD0D502635EEB67E3D36203E26CBB59A.Tại sao không phải là getSession() trả về cùng một phiên trong các yêu cầu tiếp theo trong khoảng thời gian ngắn?

Về phía server tôi cố gắng để có được phiên:

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

Nếu tôi in những biến cho cả yêu cầu tôi nhận được,
request1:

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

request2:

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

Như bạn có thể thấy, máy chủ đã tạo rõ ràng một phiên mới cho request2 trên request.getSession(). Nhưng tại sao nó làm điều này? Nó về lý thuyết nên được đồng bộ hóa và cung cấp cho bạn cùng một phiên mà yêu cầu đầu tiên (đã đạt đến mã này đầu tiên) được tạo ra. Bây giờ, để đảm bảo rằng việc tạo phiên được đồng bộ hóa, tôi đã làm như sau:

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

và tôi nhận được kết quả tương tự.

Nếu tôi gửi các yêu cầu tương tự sau đó một lần nữa (cho phép nói request1' và request2 ') tôi nhận được,
request1':

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

request2' :

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

Nếu bạn thấy chặt chẽ nay, phiên id là như nhau (trong request1' và request2') và là cái cuối cùng được tạo từ request2. Có cách nào để tôi nhận được cùng một phiên từ nhiều yêu cầu tiếp theo đến máy chủ trong các khung thời gian rất ngắn không?

Tôi không sử dụng bất kỳ tính năng đặc biệt nào - Tôi đang sử dụng chiến lược phiên của hộp thư của Spring.Ngoài ra, có vẻ như cookie JSESSIONID từ các yêu cầu frist 2 (request1 và request2) đến từ lần đầu tiên tôi truy cập trang (cho phép nói rằng có một request0 được gửi tới máy chủ khi nó tạo ra JSESSIONID này). Nhưng nó cũng có vẻ như trừ khi bạn gọi một cách rõ ràng request.getSession(), backend/server sẽ luôn tạo một JSESSIONID mới cho mọi phản hồi và gửi nó trở lại máy khách. Vì vậy, khi một yêu cầu mới được gửi từ máy khách sau khi một phản hồi đến, nó sẽ có một JSESSIONID mới. Có vẻ như Spring ra khỏi xử lý phiên hộp không hoạt động phù hợp.

Kind Regards,
bạo chúa

BỔ SUNG NGHIÊN CỨU:

tôi muốn xem liệu tôi có thể đăng ký thành lập phiên với một HttpSessionListner. Bằng cách này tôi có thể thấy khi phiên có id FD0D502635EEB67E3D36203E26CBB59A (cookie đang được gửi trong request1 và request2) được tạo. Và cũng có thể, thời tiết sử dụng người nghe (SessionProcessor) tôi có thể lưu trữ các phiên trong một bản đồ bằng id và sau đó lấy chúng bằng id từ cookie (vì vậy tôi không cần tạo một phiên khác).
Vì vậy, đây là mã:

public interface ISessionProcessor extends ISessionRetriever, ISessionPopulator { 
} 

public interface ISessionRetriever { 

    HttpSession getSession(String sessionId); 
} 

public interface ISessionPopulator { 

    HttpSession setSession(String sessionId, HttpSession session); 
} 

Lý do để tách những là vì tôi chỉ muốn cho phép người nghe để thêm phiên bản đồ, và các bộ điều khiển duy nhất để có thể tạo ra một phiên thông qua yêu cầu. getSession() - vì vậy phương thức sessionCreated của listner được gọi luôn (như bạn sẽ thấy bên dưới).

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

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

trong my-servlet-context.xml:

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

trong điều khiển của tôi :

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

Điều này đã cho tôi kết quả tương tự. Nó xuất hiện rằng việc tạo phiên bằng phương tiện khác với request.getSession (khi bản thân mùa xuân ra khỏi hộp tạo ra phiên), hoặc là không được đăng ký bởi người nghe hoặc cookie/jsessionID đến từ một nơi khác. Hãy tìm câu trả lời để biết thêm.

nguồn khác đó đã giúp tôi trải qua những vấn đề HttpSession:
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
một số công cụ tham khảo mùa xuân:
session management
session management in security
thảo luận về làm thế nào để có được phiên khi bạn có một sessionId (w mũ tôi đã làm ở trên):
coderanch discussion
stackoverflow
the post that helped me finalize my listener autowiring

Trả lời

1

nó trông giống như JSESSIONID cookie từ các But 2 yêu cầu (request1 và request2) đến từ lần đầu tiên tôi truy cập vào trang (cho phép nói rằng có một request0 được gửi đến máy chủ khi nó tạo ra JSESSIONID này).

Điều này không đúng. Tôi có 2 ứng dụng được triển khai trong cùng một miền trên cùng một máy chủ. Vì vậy, khi tôi đang gọi http://mydomain.com/app1/initpage máy chủ đã tạo phiên cho app1 có id FD0D502635EEB67E3D36203E26CBB59A và đã gửi JSESSIONID này trong cookie cho khách hàng. Khách hàng đã lưu cookie dưới tên miền mydomain.com và lần thứ hai khi tôi thực hiện http://mydomain.com/app2/executeService, trình duyệt của khách hàng đã gửi JSESSIONID từ cookie trong tiêu đề yêu cầu. Tôi đã nhận được nó trên máy chủ nhưng đây không phải là một phiên trong app2 khác.

Điều này giải thích thực tế là khi tôi gửi hai yêu cầu khác (request1 'và request2') chúng có sessionID được tạo trên ứng dụng thích hợp.

Có một cái nhìn thêm ở đây:
Deploying multiple web apps in same server
Under what conditions is a JSESSIONID created?

Đối với câu trả lời cụ thể cho câu hỏi của tôi, nó xuất hiện mà bạn cần phải thực hiện yêu cầu 1 đồng bộ, do đó bạn luôn chắc chắn rằng bạn có cùng một id phiên trong các yêu cầu sau. Các yêu cầu sau sau lần đầu tiên, có thể không đồng bộ.

0

Chỉ cần lưu trữ cookie của bạn (với JESSIONID) trong Máy khách, khi bạn gửi yêu cầu tiếp theo tới Máy chủ, đặt cookie đã lưu trong trường tiêu đề yêu cầu của bạn và gửi, sau đó bạn sẽ nhận được cùng một phiên ở cuối máy chủ.

KHÁCH HÀNG (IOS) lưu trữ cookie của bạn từ phản ứng:

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

KHÁCH HÀNG (IOS) gửi yêu cầu tiếp theo của bạn với cookie:

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

Không chỉ cho IOS khách hàng.Sau đó, vào cuối máy chủ, bạn sẽ nhận được cùng một phiên:

Server (JavaEE) GET HttpSession:

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

tôi nhận thấy rằng nó sẽ xảy ra khi các tập tin cookie bị vô hiệu hóa trong ...web.xml file:

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

Phải là <property name="enableCookies" value="false"/> để giữ lại ID phiên từ cùng một kết nối.

Các vấn đề liên quan