본문 바로가기

개발/JAVA

[Servlet] #06. Cookie(쿠키) :: id, pwd, 방문횟수

■ 쿠키 프로세스 

쿠키는 리퀘스트와 리스폰스에 쿠키 정보를 추가하여 클라이언트의 상태를 파악하기 위한 도입되었으며 클라이언트의 로컬(브라우저)에 저장되는 key-value 형태의 작은 텍스트 데이터 파일이다. 보통 이름(key), 값(value), 만료 날짜, 경로 정보 등을 포함한다.

브라우저가 특정 웹 페이지에 접속하거나 리소스를 요청한다. 그러면 서버는 요청받은 웹 페이지나 리소스와 함께 쿠키도 발행하여 함께 전송한다. 클라이언트는 전송받은 쿠키를 로컬에 저장한다.

그 다음 번에 클라이언트가 같은 웹 페이지(서버)에 접속하거나 리소스를 요청할 때 갖고있던 쿠키를 함께 보낸다. 서버는 클라이언트가 보낸 쿠키를 확인하여 어느 클라이언트에서 접속했는지 서버 상의 기록을 확인하여 이전 상태를 알 수 있다.

쿠키는 자동 로그인, 오늘 또는 일정 기간 동안 더 이상 창을 보지 않음, 쇼핑몰의 장바구니 등에 이용된다.

 

■ 쿠키의 단점

완벽한 기술은 없듯 쿠키도 단점이 존재한다.

  1. 용량
  2. 쿠키는 클라이언트에 최대 300개까지 저장할 수 있으며 한 쿠키의 용량은 최대 4kb로 제한된다. 또 하나의 도메인 당 20개의 값을 가질 수 있다.
  3. 보안
  4. 클라이언트의 로컬에도 저장되고 HTTP 요청에도 함께 포함되어 전송된다. 전송될 때 별다른 암호화를 거치지 않으므로 로컬이나 요청이 도청 당하면 개인정보가 유출되는 등의 문제가 발생할 수 있다.
  5. 리소스
  6. 작은 용량이지만 매 HTTP 요청에 포함되어 전송되므로 필요하지 않을 경우엔 리소스의 낭비라고 볼 수 있다.

더보기
더보기

■ 쿠키란?

  • 쿠키는 클라이언트(브라우저) 로컬에 저장되는 키와 값이 들어있는 작은 데이터 파일입니다.
  • 사용자 인증이 유효한 시간을 명시할 수 있으며, 유효 시간이 정해지면 브라우저가 종료되어도 인증이 유지된다는 특징이 있습니다.
  • 쿠키는 클라이언트의 상태 정보를 로컬에 저장했다가 참조합니다.
  • 클라이언트에 300개까지 쿠키저장 가능, 하나의 도메인당 20개의 값만 가질 수 있음, 하나의 쿠키값은 4KB까지 저장합니다.
  • Response Header에 Set-Cookie 속성을 사용하면 클라이언트에 쿠키를 만들 수 있습니다.
  • 쿠키는 사용자가 따로 요청하지 않아도 브라우저가 Request시에 Request Header를 넣어서 자동으로 서버에 전송합니다.

쿠키의 구성 요소

  • 이름 : 각각의 쿠키를 구별하는 데 사용되는 이름
  • 값 : 쿠키의 이름과 관련된 값
  • 유효시간 : 쿠키의 유지시간
  • 도메인 : 쿠키를 전송할 도메인
  • 경로 : 쿠키를 전송할 요청 경로

 쿠키의 동작 방식

  1. 클라이언트가 페이지를 요청
  2. 서버에서 쿠키를 생성
  3. HTTP 헤더에 쿠키를 포함 시켜 응답
  4. 브라우저가 종료되어도 쿠키 만료 기간이 있다면 클라이언트에서 보관하고 있음
  5. 같은 요청을 할 경우 HTTP 헤더에 쿠키를 함께 보냄
  6. 서버에서 쿠키를 읽어 이전 상태 정보를 변경 할 필요가 있을 때 쿠키를 업데이트 하여 변경된 쿠키를 HTTP 헤더에 포함시켜 응답

쿠키의 사용 예

- 방문 사이트에서 로그인 시, "아이디와 비밀번호를 저장하시겠습니까?"

- 쇼핑몰의 장바구니 기능

- 자동로그인 팝업에서 "오늘 더 이상 이 창을 보지 않음" 체크

 


쿠키와 세션은 저장공간이 서로 다르다. 보통 Login 정보를 많이 담는데,

이 Login 정보는 ID(String), Login(Object: id, name, pwd -> Dto) 로 불러온다. 

더보기
더보기


(1) cookie : client 공간에 저장. String 
  (ex) id, password, 방문횟수 
  - JavaScript에서 접근이 가능한 특징이 있다.

(2) session : server 공간에 저장. Object 
  저장 기한 설정, 방문 횟수 
  ※ 단, 한글을 사용할 수 없다 
  (ex) MemberDto 

우리는 여태까지 데이터를 이렇게 불러왔다.

(넘길 때) request.setAttribute(  ,  )
(받을 때) Object obj = request.getAttribute()
(보낼 때) forward

세션도 마찬가지로 상기 방식으로 데이터를 옮긴다.

session.setAttribute(   ,   )
Object obj = session.getAttribute()
forward

하지만, 위의 request.setAttribute는 일회성이라고 보면 된다.
반면, session은 시간 등을 설정할 수 있다. 
위에 방법으로 데이터가 안 갈 경우, 간혹 실무에서 종종 급한 데이터는 Session으로 보내곤 한다. 
하지만, 서버에 저장되다보니 서버의 공간은 한정적이므로 남발을 하면 안 된다.

 


 

1. index.html

▶ a 태그로 링크를 가볍게 걸어주었다.

 <a href="hello"> hello Servlet </a>

 

 


 

2. HelloServlet.java

▶ 서블릿을 하나 생성해 다음 페이지로 이동 / 쿠키를 add해준다.

package sample08;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		/*sample08 : cookie*/
		Cookie cookie = new Cookie("id", "abc123");
		resp.addCookie(cookie);
		
		cookie = new Cookie("pwd", "aaaa1111");
		resp.addCookie(cookie);
		
		
		resp.setContentType("text/html; charset=utf-8");
		
		PrintWriter pw = resp.getWriter();
		
		pw.println("<html>");
		pw.println("<head>");
		pw.println("<title>제목</title>");
		pw.println("</head>");
		
		pw.println("<body>");
		
		// pw.println("");
		pw.println("<a href=dispCookie> Cookie를 표시 </a>");
		
		pw.println("</body>");
		pw.println("</html>");
		
		pw.close();
		
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

	}

	
	
}

 


 

3. DisplayCookie.java

▶ 쿠키를 Display할 페이지를 위해 새로운 서블릿을 추가해주었다.

▶ 쿠키의 값 유무를 Check하여 출력해주는 처리를 해주었다.

▶ 추가적으로 방문 횟수를 표시하는 a 태그를 추가해주었다. (다음 서블릿 페이지로 이동)

package sample08;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/dispCookie")
public class DisplayCookie extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		resp.setContentType("text/html; charset=utf-8");
		
		PrintWriter pw = resp.getWriter();
		
		pw.println("<html>");
		pw.println("<head>");
		pw.println("<title>제목</title>");
		pw.println("</head>");
		
		pw.println("<body>");
		
		pw.println("<h3>Cookie Display</h3>");
		
		Cookie cookies[] = req.getCookies();
		
		// 쿠키가 없을 경우
		if(cookies != null) {
			
			for (int i = 0; i < cookies.length; i++) {
				String cookieName = cookies[i].getName();
				String value = cookies[i].getValue(); 
				
				pw.println("<p>" + cookieName + ":" + value + "</p>");
				
			}
		}		
		
		// 방문 횟수
		pw.println("<a href=VisitedCookie> 방문횟수를 표시 </a>");	
	
		pw.println("</body>");
		pw.println("</html>");
		
		pw.close();		
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		super.doPost(req, resp);
	}

}

4. VisitedCookie.java

▶ 방문 횟수를 저장하고, 쿠키를 검색 및 생성, 갱신 처리를 해주는 서블릿을 추가해준다.

▶ 방문 횟수에 Count가 추가되는 처리를 해준다.

package sample08;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/VisitedCookie")	// namespace
public class VisitedCookie extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.setContentType("text/html; charset=utf-8");
		
		PrintWriter pw = resp.getWriter();
		
		
		// 방문횟수 저장
		pw.println("<html>");
		pw.println("<head>");
		pw.println("<title>제목</title>");
		pw.println("</head>");
		
		pw.println("<body>");
		
		// pw.println("");
		pw.println("<p> 방문 횟수 </p>");
		
		Cookie cookies[] = req.getCookies();
		Cookie visitedCookie = null;			// Key Value로 관리하기 위한 쿠키를 만들어두었다
		
		if(cookies != null) {
			// 검색, 우리가 설정한 쿠키가 맞는지?
				for (int i = 0; i < cookies.length; i++) {
					if(cookies[i].getName().equals("visited")) {
						visitedCookie = cookies[i];			// 쿠키명도 충돌나면 안 된다! 새 데이터가 덧 씌워진다고 보면 된다. 찾은 데이터
						break; 										// 찾았으니 더 이상 루프를 돌릴 필요가 없다. 
					}
				}
			
			// 해당 쿠키를 찾았을 때, 기존에 있던거니까 플러스 해준다
			if(visitedCookie != null) {
				int count = Integer.parseInt( visitedCookie.getValue() ) +1; 	// count에 방문 횟수가 계속 추가
				pw.println("<p>" + count + "번째 방문입니다 </p>");
				
				// 그리고, cookie 값을 갱신
				visitedCookie.setValue(count + "");
				
				// 기간 설정
				visitedCookie.setMaxAge(60); 			// 365 * 24 * 60 * 60 -> 1년. 쿠키는 보통 기간을 길게 준다. 
				
				resp.addCookie(visitedCookie); 			// 갱신된 값을 다시 출력
				
				
			}
			// 못 찾았을 때, 하나도 없다는 뜻이므로 여기서 쿠키를 생성해주어야 한다
			// 참고로, 쿠키는 프로그램 끄더라도 계속 저장되어 있다.
			else {
				pw.println("<p>첫 번째 방문입니다</p>");
				Cookie newCookie = new Cookie("visited", "1");		// 쿠키 명칭 : visited
				resp.addCookie(newCookie);
			}
			
		} else {
				
		}
		
		pw.println("</body>");
		pw.println("</html>");
		
		pw.close();
		
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		super.doPost(req, resp);
	}

}

 


계속적으로 refresh하면 다음과 같이 Count가 증가된다

 


Reference

https://interconnection.tistory.com/74
https://www.gracieuxyh.dev/web/cookie-and-session-and-storage/