[Servlet] 5. Cookie & Session
Cookie & Session 개요
1. HTTP 통신
(1) HTTP 통신 방법
- HTTP: 서버, 클라이언트 간의 요청과 응답으로 데이터를 주고받는 형식
- 서버는 클라이언트의 요청에 응답을 완료하면 연결을 끊는다. 즉, 한 번의 요청, 응답이 끝나면 연결을 끊는다.(stateless)
-> 클라이언트는 요청을 또 보내고 싶으면 새로 연결해야 한다.
(2) HTTP 통신의 특징
1) 무연결
- HTTP는 요청할 때 잠깐, 응답할 때 잠깐만 연결하는 무연결의 특징을 갖는다.
- 기본적으로 HTTP는 TCP 프로토콜(=연결지향 프로토콜로 요청 시 서버가 수락해야 송수신 가능)에
특화 기능을 추가해서 사용하는 것이다.
2) 무상태
- 서블릿 컨테이너 내에는 여러 개의 서블릿이 있는데,
각각의 서블릿에서 상태값(속성, 변수값)을 다른 서블릿에서 공유해 쓸 수 없음을 의미한다.
(3) HTTP 통신의 문제점
- 연결이 끊어지면서 유지되어야 하는 정보가 사라지는 문제가 발생한다.
ex) 로그인 후의 로그인 계정 정보, 장바구니에 넣은 데이터 등
ㄴ> 정보를 기억하고 싶기 때문에 해결책으로 나온게 쿠키와 세션이다. (쿠키는 클라이언트 측, 세션은 서버 측에 데이터를 보관)
Cookie
1. Cookie란?
: 클라이언트 측, 즉 사용자 컴퓨터에 데이터를 텍스트 파일 형태로 저장하는 기술로,
필요 시에 저장한 정보를 서버와 공유하여 정보를 유지한다.
- 패키지: jakarta.servlet.http.Cookie
- 서블릿에서 쿠키 정보를 설정해주면, 쿠키를 클라이언트가 가지고 있으면서 다른 서블릿에 요청할 때 담아 보낸다.
- 데이터는 map 형식으로 저장되고, 데이터의 크기, 개수에 제한이 있다.
- Cookie 유지 시간, 유효 디렉토리, 유효 도메인 등을 설정할 수 있다.
ㄴ> 즉, 호출(조회)한 데이터를 클라이언트 PC에 가지고 있도록 하는 것으로 cookie에 대한 보관 정보는 클라이언트가 주축이다.
- Cookie는 간단하게 이용할 수 있다는 장점이 있지만,
공용 PC를 사용하거나 URL에 일부 데이터를 포함하는 경우 보안에 취약하다.
2. Cookie 속성 설정하기
1. name = value
- ASCII 문자만 사용 가능하며, 한 번 설정된 쿠키의 name은 수정할 수 없다.
- 쿠키의 이름에는 공백문자와 일부 특수문자(()=,"\?@:;)를 사용할 수 없다.
2. expire = '날짜'
- cookie의 유지 시간으로, 설정이 따로 없으면 브라우저 동작동안 유지한다.
3. path = '경로'
- cookie가 전달되는 서버의 유효 디렉토리를 지정하는 속성이다.
4. domain = '서버정보'
- cookie가 전달되는 유효 서버를 설정한다.
5. secure
- https나 ssl보안 프로토콜로 요청할 때만 서버에 전송한다.
3. Cookie 설정 및 전송하기
@WebServlet("/cookie")
public class CookieHandlerServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String firstName = req.getParameter("firstName");
String lastName = req.getParameter("lastName");
System.out.println("firstName: " + firstName + " lastName: " + lastName);
/*1. 쿠키 생성*/
Cookie firstNameCookie = new Cookie("firstName", firstName);
Cookie lastNameCookie = new Cookie("lastName", lastName);
/*2. 쿠키 만료 시간 설정*/
firstNameCookie.setMaxAge(60 * 60 * 24); // 초 단위이며 하루를 만료시간으로 하는 예시
lastNameCookie.setMaxAge(60 * 60 * 24);
/*
<Cookie 설정값 지정하기>
setMaxAge(int expiry): 유효 시간 설정
setPath(String url): 경로 설정(서버의 모든 요청이 아닌 특정 경로를 통한 요청으로 cookie를 사용하는 경우)
setDomain(String domain): cookie 도메인 설정 및 cookie 생성(도메인 외의 도메인 설정 시 사용)
*/
// 3. 응답 헤더에 쿠키를 담는다.
resp.addCookie(firstNameCookie);
resp.addCookie(lastNameCookie);
// 4. 응답 처리
resp.sendRedirect("redirect");
}
}
4. 전송한 cookie 활용하기
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/* redirect 처리 시 이전 req 정보는 존재하지 않는다. 새로운 req 객체이므로 값이 없어 null이 반환 된다. */
String firstName = req.getParameter("firstName");
String lastName = req.getParameter("lastName");
System.out.println("firstName: " + firstName + ", lastName: " + lastName);
// 저장 된 쿠키 값을 꺼내서 확인(배열 형태로 읽어온다.)
Cookie[] cookies = req.getCookies();
for(Cookie cookie : cookies) {
if(cookie.getName().equals("firstName")) {
firstName = cookie.getValue();
} else if(cookie.getName().equals("lastName")) {
lastName = cookie.getValue();
}
}
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.println("<h1>your first name is " + firstName + " and last name is " + lastName + "</h1>");
out.flush();
out.close();
}
}
* 참고
<!--index.jsp-->
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<title>Cookie</title>
</head>
<body>
<h1>Cookie Handling</h1>
<form action="cookie" method="post">
<table>
<tr>
<td>firstName : </td>
<td><input type="text" name="firstName"></td>
</tr>
<tr>
<td>lastName : </td>
<td><input type="text" name="lastName"></td>
</tr>
<tr>
<td colspan="2"><button>전송</button></td>
</tr>
</table>
</form>
</body>
</html>
5. cookie 확인하기
Chrome의 경우,
브라우저에서 '개발자도구(F12) -> Application -> Cookies' 에 가면 확인할 수 있다.
저장경로는 'C:\Users\user\AppData\Local\Google\Chrome\UserData\Default\Cache' 이다.
Session
1. Session이란?
: 클라이언트 측에 데이터를 저장하는 cookie와 달리 서버에 데이터를 저장하는 기술로, 클라이언트에는 session ID를 부여한다.
- Cookie의 보안상 단점과 지원하는 브라우저 문제 등으로 인해 상태를 유지해야 하는 메커니즘에 적합하지 않은 경우
session 인스턴스를 이용해서 상태를 유지하는 메커니즘을 제공한다.
- 클라이언트가 요청 시 session ID를 보내면
일치하는 session 정보(객체)를 컨테이너가 생성하여 그 객체의 데이터를 사용할 수 있다.
ㄴ> 즉, 브라우저마다 제공하는 HashMap으로 서버에서 클라이언트에게 제공한다.(session ID가 key, 데이터가 value)
Session에 값을 넣으면 모든 서블릿에서 해당 session ID로 고유 공간을 찾아 값을 공유해 사용할 수 있다.
- 패키지: jakarta.servlet.http.HttpSession
- 데이터를 서버에서 관리하므로 보안상 안전하고, 브라우저가 종료되면 세션도 함께 소멸한다.
- 만일 클라이언트가 보낸 session ID가 없으면 새로 세션 객체를 생성한다.
2. 데이터 상태 저장 영역
- Page scope: 하나의 servlet, 하나의 class에서만 공유 가능
- Request scope: forward에 한정해 공유할 수 있는 범위
- Session scope: redirect 방식에서도 활용할 수 있는 범위
(ex. 로그인 정보 - 사용자가 사용하는 모든 페이지에서 사용자의 정보를 가지고 있어야 하기 때문)
- Application scope: 브라우저별 정보보다 넓은 범위
3. session 이용하기
@WebServlet("/session")
public class SessionHandlerServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/* session 생성하기 - session은 직접 생성할 수 없고,
request 객체의 getSession()을 이용해 반환받을 수 있다.*/
HttpSession session = req.getSession();
/* session은 브라우저 당 한 개의 고유 아이디를 가지고 하나의 인스턴스를 이용한다.
* 반복 요청(새로고침) 시 동일 session id를 반환한다.
* 단, 브라우저가 종료 되면 해당 세션이 종료 되므로 그 이후의 요청은 다른 session id를 반환한다.
* session id는 cookie로 보관되고 있다.*/
System.out.println(session.getId());
/*session 유지시간 설정*/
System.out.println(session.getMaxInactiveInterval()); // 세션의 기본 유지시간은 30분
session.setMaxInactiveInterval(60 * 10); // 필요에 따라 늘이거나 줄일 수 있다 (10분)
System.out.println(session.getMaxInactiveInterval());
/* session은 redirect 해도 값을 유지할 수 있으므로 request 보다 더 넓은 범위의 공유 영역이라고 할 수 있다. */
String firstName = req.getParameter("firstName");
String lastName = req.getParameter("lastName");
/*session 속성값 설정*/
session.setAttribute("firstName", firstName);
session.setAttribute("lastName", lastName);
resp.sendRedirect("redirect");
}
}
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/* session id를 통해 session 인스턴스를 가져온다. */
HttpSession session = req.getSession();
System.out.println("redirect session id : " + session.getId());
/* 세션 인스턴스에 저장 된 attribute는 다른 요청에서 꺼내서 쓸 수 있다. */
String firstName = (String) session.getAttribute("firstName");
String lastName = (String) session.getAttribute("lastName");
System.out.println(firstName + " " + lastName);
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.println("<h1>your first name is " + firstName + " and last name is " + lastName + "</h1>");
out.flush();
out.close();
}
}
@WebServlet("/delete")
public class DeleteSessionDataServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
Enumeration<String> keys = session.getAttributeNames();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
System.out.println(key + " = " + session.getAttribute(key));
}
/* session 데이터를 제거하기
* 1. 설정 만료 시간이 지나면 session 자동 만료
* 2. removeAttribute()로 속성 제거 (특정값만 지우고 싶을 때)
* 3. invalidate()로 session의 모든 데이터 제거(session 무효화, 강제 만료)*/
System.out.println("=================================");
session.removeAttribute("firstName");
keys = session.getAttributeNames();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
System.out.println(key + " = " + session.getAttribute(key));
}
System.out.println("=================================");
session.invalidate();
keys = session.getAttributeNames();
while(keys.hasMoreElements()){
String key = keys.nextElement();
System.out.println(key + " = " + session.getAttribute(key));
}
}
}
* 참고
<!--index.jsp-->
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<title>Session</title>
</head>
<body>
<h1>Session Handling</h1>
<form action="session" method="post">
<table>
<tr>
<td>firstName : </td>
<td><input type="text" name="firstName"></td>
</tr>
<tr>
<td>lastName : </td>
<td><input type="text" name="lastName"></td>
</tr>
<tr>
<td colspan="2"><button>전송</button></td>
</tr>
</table>
</form>
<hr>
<a href="delete">세션 데이터 지우기</a>
</body>
</html>
4. Session Method
method 명 | 내용 |
setAttribute(String, object) | request객체에 전달하고 싶은 값을 String 이름-Object 값으로 설정 |
getAttribute(String) | 매개변수와 동일한 객체의 속성 값 가져옴 |
getAttributeNames() | 객체에 등록되어 있는 모든 속성의 이름만 반환 |
removeAttribute(String) | request객체에 저장된 매개변수와 동일한 속성 값 삭제 |
getId() | SessionID값 가져옴 |
getCreationTime() | Session객체가 생성된 시간 반환 (msec) |
getMaxInactiveInterval() | client 요청이 없을 때, 서버가 현재 Session을 언제까지 유지할지 초 단위로 반환 (default = 30분) |
getLastAccessedTime() | client 요청이 마지막으로 시도된 시간 반환 (msec) |
isNew() | 새로 생성된 Session이면 true, 아니면 false 반환 |
invalidate() | 현재 Session 삭제 |
setMaxInactiveInterval(int) | 객체 유지 시간을 설정하고, 지정 시간 지나면 객체 자동 삭제 |