Spring Framework/Servlet

[Servlet] 5. Cookie & Session

hyomee2 2024. 9. 2. 00:53

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) 객체 유지 시간을 설정하고, 지정 시간 지나면 객체 자동 삭제

 

'Spring Framework > Servlet' 카테고리의 다른 글

[Servlet] 4. Forward와 Redirect  (0) 2024.08.30
[Servlet] 3. Servlet Method  (0) 2024.08.29
[Servlet] 2. Servlet LifeCycle  (1) 2024.08.28
[Servlet] 1. Servlet 개요  (1) 2024.08.28