Java HttpSession(javax.Servlet.Http) 소개
HttpSession은 Java의 인터페이스(interface)이며, 이를 사용하여 세션(session)을 제어할 수 있습니다.
session은 쿠키(cookie)의 트래픽(traffic) 이슈(issue)와 cookie 변경으로 인한 보안 issue를 해결하기 위해 등장했습니다.
- servlet container는 웹(web) container라고도 불리며, Tomcat, JBoss(현재 WildFly), Jetty 등이 대표적입니다.
- servlet container와 servlet은 다릅니다.
- servlet container는 server에서 servlet 생명 주기(life cycle) 관리, request에 따른 스레드(thread) 생성, 동적(dynamic) resource(JSP, servlet 등) 생성 등 servlet과 상호 작용하는 web server의 일부입니다.
- servlet은 javax.servlet package에 정의된 interface이며, JVM(java virtual machine) 내에서 실행되는 web application의 작은 조각입니다.
- HttpSession object 생성
- {HttpServletRequestObject}.getSession() : // 기존 session이 있으면 기존 session object를, 없으면 새로 생성 후 반환
- {HttpServletRequestObject}.getSession(false) // 기존 session이 있으면 기존 session object를, 없으면 null 반환
- HttpSession Method
- setAttribute(String, Object)
- getAttribute(): Object
- getCreationTime(): long
- getLastAccessedTime(): long
- setMaxInactiveInterval(int second) // client가 설정 시간 동안 request가 없으면 session 만료
- getMaxInactiveInterval(): int
invalidate() : // session 종료(session에 속한 속성들도 함께 제거)- getId() : String // SessionId 반환
Tomcat은 WAS? No! Just Servlet Container!]
JAVAEE는 엔터프라이즈 어플리케이션을 위해 만든 표준이고, 수많은 클래스/인터페이스로 정의되어 있습니다.
JAVAEE 6.0의 스펙을 보면, Web Services, Web Application, Enterprise Application, Management and Security 기술들을 정의하고 있습니다.
그리고 이 스펙을 모두 구현한 모델을 WAS라고 칭합니다.
우리가 흔히 WAS로 알고 있는 tomcat은 JAVAEE 스펙의 일부만 구현하고 있어, WAS가 아니라 Servlet Container 입니다.
즉 우리가 웹어플리케이션을 개발할 때 사용하는 HttpSession도 Servlet Container가 생성한 인스턴스이다.
Spring은 Servlet Container가 만든 HttpSession을 주입할 뿐, HttpSession을 생성하는 주체는 Servlet Container이다.
(참고로 SpringSession을 이용한다면 Servlet Container가 생성한 구현체가 아니라 SpringSession이 생성한 구현체가 될 것.
모든 요청에 대해 Session을 만들까?
아니다. Session을 만드는 것 자체도 부담이 가는 일이기 때문에, Session을 사용할 때만 생성한다.
Spring Web MVC에서는 HttpSession을 주입해야 할 때, 내부적으로 Servlet Container에게 Session을 달라고 한다.
httpServletRequest.getSession()
그리고 그 때 Servlet Container가 HttpSession을 생성해준다. Spring이 Servlet Container에게 Session을 달라고 하는 시점은 HttpSession을 사용하는 방법에 따라 약간씩 다르다.
HttpSession을 주입받는다고 선언하는 것만으로는 Servlet Container에게 Session을 달라고 요청하지 않는다. setAttribute 혹은 getAttribute 같은 api를 호출하는 시점에 요청/생성한다.
이렇게 메소드에서 매개변수를 통해 주입받는 방식으로 구현하는 경우엔, 선언시에 Servlet Container에게 Session을 달라고 요청한다. 따라서 위의 예제에서는 getList 메소드를 호출하는 즉시 Session이 요청/생성된다.
HttpSession 인터페이스는 둘 이상의 page request에서 사용자를 식별하거나, 웹 사이트를 방문하고 해당 사용자에 대한 정보를 저장하는 방법을 제공한다.
Servlet container는 HttpSession를 사용하여 HTTP client - HTTP server 간의 세션을 생성한다. 이 때, 세션은 한 명의 사용자에 해당한다. 서버는 Cookie, rewriting URL와 같은 방법으로 세션을 유지하면서 관리할 수 있다. 객체를 세션에 바인딩하여 사용자 정보를 유지할 수 있다.
// 값 저장 HttpSession's setAttribute("Key", Value)
- "Key"를 사용하여 객체를 세션에 바인딩한다.
Value는 값으로 들어올 자료형을 예측할 수 없기에 Object형으로 업캐스팅하여 모두 받아낸다.
// 값 얻기 HttpSession's getAttribute("Key")
- "Key"로 바인딩된 객체를 돌려주고, "Key"로 바인딩된 객체가 없다면 null를 돌려준다.
Value는 세션을 저장할 때 Object형으로 업캐스팅을 했으므로, 가져올 땐 원래대로 다운캐스팅 해야 한다.
// 생성 HttpServletRequest's getSession(true)
- 이미 세션이 있다면 그 세션을 돌려주고, 세션이 없으면 새로운 세션을 생성한다.
request.getSession()로 쓸 수 있다.
HttpSession session = request.getSession();
// 생성 HttpServletRequest's getSession(false)
- 이미 세션이 있다면 그 세션을 돌려주고, 세션이 없으면 null을 돌려준다.
HttpSession session = request.getSession(false);
// 값 제거
- session.removeAttribute(String name);
// 특정 이름의 속성 제거
- session.invalidate(); // binding 되어 있는 모든 속성 제거
[Session]
[동작순서]
[특징]
HttpSession 객체
해결방안
쿠키 vs 세션
쿠키 :
- 브라우저를 통해 클라이언트에 저장되는 사용자 정보
- (name, value) 쌍으로 이루어진 정보
- 초기에 웹 서버에 의해 HTTP Header에 포함되어 클라이언트에게 전송
- 이후에 접속마다 클라이언트가 웹 서버에게 재전송
- 보안적 취약성으로 인해 중요 정보를 저장하지 않아야 함
세션 :
- 사용자 정보를 서버에 저장
- 클라이언트의 최초 접속 시 새로운 세션을 생성하고 세션 ID 전송
- 이후 접속마다 클라이언트가 세션 ID 재전송
- 서버는 세션 ID에 해당하는 세션 정보를 획득
- 세션 ID 전송 수단으로 쿠키를 사용할 수 있음
세션 관리
ex ) HttpSession session = request.getSession();
생성된 세션이 없었던 경우
기존 세션이 있는 경우
HttpSession Interface
- boolean isNew() : 이번 요청으로 새로운 세션이 생성되었는지의 여부를 리턴
- String getid() : 현재의 세션 ID를 리턴
- void invalidate() : 현재 세션 종료
- long getCreationTime() : 세션이 생성된 시간 제공
-long getLastAccessedTime() : 마지막으로 세션에 관련된 클라이언트가 요청을 보낸 시간 제공
-void setMaxInactiveInterval(int) : 초단위로 최대 유휴기간 설정
-int getMaxInactiveInterval() : 초단위로 설정된 최대 유휴기간 리턴- void setAttribute(String, Obect)
- Object getAttribute(String)
세션 Lifecycle
- 생성 : 최초로 request.getSession()이 호출될 때 container가 생성
- 사용 : 클라이언트가 세션 ID를 이용해 접속, request.getSession()을 통해 사용중인 HttpSession 객체 획득 후 사용
- 종료 : invalidate()가 호출되거나, 세션이 타임아웃 되었을 때 container가 소멸
HttpSession.getAttribute("user")
- 사용자 A가 접속해도 "uesr" 를 key로 값을 가져오고,
사용자 B가 접속해도 "user" 를 key로 가져온다.
같은 key를 쓰는데 어떻게 A 와 B를 구분해서 값을 가져올 수 있을까?
Session은 각 클라이언트 마다 하나씩 생성되어 제공이 된다.
그렇기 때문에 HttpSession.getAttribute("user")를 해도 서로 다른 값이 보이도록 된다.
단순하게 말하면 클라이언트와 서버 간의 연결이 지속적으로 유지되는 상태. 즉, 웹 사이트 탐색하는 시간을 의미한다.
HTTP의 특성은 이러하다.
- HTTP는 무상태(Stateless) 프로토콜이다.
- 클라이언트와 서버가 요청과 응답을 주고 받으면 연결이 끊어진다.
- 클라이언트가 다시 요청하면 서버는 이전 요청을 기억하지 못한다.
- 클라이언트와 서버는 서로 상태를 유지하지 않는다.
session의 특성은 다음과 같다.
- 클라이언트가 처음 서버에 연결을 하면 어떤 하나의 Session ID가 생성된다.
- 이 아이디는 고유한 아이디이다.
- 이 아이디를 통해서 서버는 아 이녀석이구나 하고 요청에 대한 응답을 하게 된다.
즉, 클라이언트는 하나의 유일한 주민등록번호와 같은 것을 갖고 있는 것이다.
만약 클라이언트 하나마다 생성되는 아이디가 아예 없다면 어떻게 될까?
최동민이라는 이름으로 은행에서 출금을 하려 할 때에
은행원은 이 최동민이 누구 최동민인지를 알 수가 없다.
식별할 수 있는 고유한 값이 없다는 것이고. 그렇다면 요청에 대한 응답을 서버는 내릴 수가 없을 것이다.
참고 링크