본문 바로가기
Framework/Spring

[Spring Boot] Cookie

by 코딩하는 랄로 2024. 1. 19.
728x90

웹에서의 네트워크 연결

쿠키에 대해서 알아보기 전에 쿠키가 등장한 배경에 대해서 먼저 알아야 한다. 웹과 서버과 통신을 할 때에는 클라이언트인 웹이 서버의 request를 보내고 서버가 그에 대해서 response를 보내는 형태이다.

 

request를 보낼 때 서버와 연결을 하고 response를 받고 일정 시간이 지난 후 서버와의 연결이 끊어지게 된다. 이 때, 다시 request를 보낼 때 서버와 연결을 다시 하게 되는데, 해당 연결은 이전의 연결과는 독립적인 연결이기 때문에 서버는 request를 보낸 클라이언트가 이전과 같은 클라이어트인지를 모른다( Stateless => client에 대한 정보가 없음 )

 

이런 경우에 생기는 문제점으로는 다음의 상황들을 가정해보면 이해하기 쉽다. 

  • 쇼핑 웹에서 장바구니에 물건을 다 담고 F5으로 페이지를 리로딩했더니 장바구니가 텅 비어져있음.
  • 로그인을 하고 다른 페이지로 이동했더니 로그인이 안 되어 있다고 함.

이 외에도 클라이언트의 상태에 대해서 알아야 하는 경우에 서버와의 통신의 연속성이 없어 그에 대해 알기가 어려워지는 경우가 많다. 이를 해결하기 위해 등장한 것이 바로 쿠키와 세션이다. 이번 글에서는 그 중에서 쿠키에 대해서 알아보고 Spring에서 쿠키를 다뤄보자.

 

 

Cookie 란

쿠키는 웹 서버가 생성하여 웹 브라우저로 전송하는 작은 정보 파일이다. 이 정보 파일을 클라이언트에서 보관하고 있다가 그 다음 웹 서버에 요청할 때, 같이 보내게 되고 웹 서버는 쿠키 파일을 통해 클라이언트의 정보를 알 수 있게 되는 것이다.

 

때문에 이제는 쇼핑 웹사이트에서 장바구니에 물건을 담고 새로고침을 해도 장바구니가 비워지지 않게 된다. 그렇다면 쿠키는 어디에 저장될까? 쿠키는 웹 브라우저가 사용자 기기의 저장을 한다. 대표적인 웹 브라저인 Google Chrome은 Cookies라는 파일에 모든 쿠키를 저장하고 이는 개발자 도구의 애플리케이션 탭에서 저장된 쿠키를 확인할 수 있다.

 

 

Cookie 사용 용도

쿠키는 여러 용도로 사용되는데, 어떤 용도로 주로 사용되는지 알아보자.

 

사용자 세션

대표적으로 사용되는 용도 중 하나일 것이다. 쿠키에 웹 사이트 활동을 하는 사용자에 관한 정보를 저장하고 이 정보를 토대로 서버에서 동적으로 웹페이지를 형성하여 보여줄 수 있게 되는 것이다. 위에서 다루었던 유저가 로그인하였을 때 다른 페이지로 넘어가더라도 로그인에 대한 정보를 저장하고 있어 계속해서 로그인하는 번거로움도 없어지고 장바구니가 비워지는 불편함도 없어지는 것이다.

 

개인화

해당 용도도 웹 브라우저를 이용하면서 많이 경험해보았을 것이다. 예를 들어 특정 웹사이트에서 로그인하고 로그아웃한 뒤 다시 로그인하려고 하였을 때 최근에 로그인한 방식( ex. kakao, google 등 )을 보여주는 등 웹 브라우저를 사용하는 개인에게 맞춰 웹 페이지를 제공하는 용도로 사용된다.

 

추적

추적 또한 위의 용도와 결이 크게 다르지 않다. 해당 용도는 주로 사용자의 행동을 추적하는 것인데 구글에서 쇼핑 웹사이트에서 들어가서 이런 저런 제품을 보다가 다시 구글로 돌아왔을 때 그와 관련된 광고들이 뜬 것을 경험한 적이 있을 것이다. 이 또한 쿠키를 추적하여 사용자의 행동과 관련된 정보들을 제공한 것이다.

 

 

Spring Boot에서 쿠키 사용

Spring Boot에서 쿠키를 다루는 방법으로는 두가지가 있다.

  • HttpServletRequest/Response 객체
  • @CookieValue("key")

각각의 방법으로 쿠키를 다루는 방법을 알아보자.

 

HttpServletRequest/Response

먼저, Spring Control로 요청이 들어오면 쿠키를 생성하여 보내주는 동작을 구현해보자. 이를 위해 다음과 같은 과정을 거친다.

  • 쿠키(Cookie) 객체 생성 => servlet에서 제공해주는 Cookie 클래스가 있음
  • 쿠키 속성 설정 => setter, ex. 쿠키의 만료 기간 등
  • HttpServletResponse 객체에 쿠기 담기

위의 과정을 토대로 코드를 작성해보자.

@RequestMapping("/cookie/create")
@ResponseBody
public String create(HttpServletResponse response){
    String cookieName1 = "randomNumber";
    String cookieValue1 = "" + (int)(Math.random() * 10);
    Cookie cookie1 = new Cookie(cookieName1, cookieValue1);  // name-value 로 Cookie 생성

    cookie1.setMaxAge(30);  // 쿠키 파기(expiry) 시간 설정 (생성 시점으로부터 30 초 후)
    response.addCookie(cookie1);  // response에 쿠키 추가

    // 여러개도 추가 가능
    String cookieName2 = "createdAt";
    String cookieValue2 = LocalDateTime.now().toString();
    Cookie cookie2 = new Cookie(cookieName2, cookieValue2);
    
    cookie2.setMaxAge(60);
    response.addCookie(cookie2);

    return "cookie 생성";
}

 

쿠키가 들어왔는지 확인만 하면 되기 때문에 ResponseBody 어노테이션을 붙여주었다. 이제 해당 경로로 요청을 보내고 관리자 도구를 통해 쿠키가 잘 생성되었는지 확인해보자. ( 관리자도구(F12) => application => cookie => url )

 

30초 뒤에 위에 재로딩 버튼( Filter 검색창 옆 )을 누르면 randomNumber는 사라지는 것 또한 볼 수 있다.

 

 

쿠키가 생성되는 것을 확인하였으니 이제 서버에서 클라이언트에서 보낸 쿠키를 받아와서 화면에 띄워보자. HttpServletRequest 객체를 통해 request에 담겨있는 쿠키 정보를 받아올 수 있다.

@RequestMapping("/cookie/list")
@ResponseBody
public String list(HttpServletRequest request) {

    Cookie[] cookies = request.getCookies();  // request의 쿠키 정보 가져오기
    StringBuilder buff = new StringBuilder();

    if(cookies != null) {  // 쿠키가 하나도 없다면 null 리턴
        for (int i = 0; i < cookies.length; i++) {
            // Cookie 는 name-value 쌍으로 이루어진 데이터 (name, value는 모두 String)
            String name = cookies[i].getName();  // 쿠키 'name'
            String value = cookies[i].getValue();  // 쿠키 'value'
            buff.append(name).append(" : ").append(value).append(" ");
        }
    } else {
        buff.append("쿠키가 없습니다");
    }
     return buff.toString();
 }

 

지금 이 상태로 cookie/list에 request를 보내면 쿠키가 존재하지 않기 때문에 다음과 같이 '쿠키가 없습니다' 를 띄우게 된다.

 

쿠키가 존재할 때, 어떤 결과를 띄우는지 보기 위해 이전에 생성했던 cookie/create 에 대한 요청이 들어오면 쿠키를 생성하고 다시 cookie/list로 리다이렉트 요청을 보내도록 아래와 같이 수정해주자.

@RequestMapping("/cookie/create")
//@ResponseBody  => redirect 해야하므로 주석 처리 해주자
public String create(HttpServletResponse response){
    
    ...

    return "redirect:/cookie/list";  // redirect
}

 

이제 cookie/create로 요청을 보내면 cookie/list로 리다이렉트 되면서 같이 보낸 쿠키 정보를 출력하는 것을 확인할 수 있다.

 

만약 쿠기를 삭제하고 싶다면, 응답을 보낼 때 원하는 쿠키의 setMaxAge()의 값을 0으로 변경하여 넘겨주면 된다.

 

 

@CookieValue("key")

@CookieValue 어노테이션은 컨트롤러의 매개변수에 붙여서 사용한다. 위의 코드에서 create 메소드를 해당 어노테이션을 사용 하는 방식으로 변경해보자. @CookieValue의 name 속성을 통해 원하는 쿠키 이름을 변수에 매핑할 수 있고 required 속성을 통해 해당 쿠키를 필수적으로 받아야 하는지 아닌지를 정해줄 수 있다.

@RequestMapping("/cookie/list")
@ResponseBody
public String list(
    @CookieValue(name="createdAt", required = false) String createdAt,
    @CookieValue(name="randomNumber", required = false) String rand
) {
    StringBuilder buff = new StringBuilder();
    if(rand != null) {  // 쿠키가 하나도 없다면 null 리턴
        buff.append("randomNumber : ").append(rand).append(" ");
    }
    if (createdAt != null) {
        buff.append("randomNumber : ").append(createdAt);
    }
    if(rand == null && createdAt == null) {
        buff.append("쿠키가 없습니다");
    }
    return buff.toString();
}

 

다시 cookie/create로 요청을 보내면 list로 리다이렉트되면서 잘 출력되는 것을 확인할 수 있다.

 

 

 

 

728x90

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

[Spring Security] 기본 설정 파일 생성  (0) 2024.01.30
[Spring Security] 동작 구조에 대한 이해  (1) 2024.01.30
[Spring Boot] Lombok  (0) 2024.01.11
[Spring Boot] Controller  (1) 2024.01.08
[Spring Boot] 게시판 목록 페이지  (0) 2024.01.08