TIL/Project

TIL 2024-12-08 (Trouble Shooting (먹GO) )

myoma 2024. 12. 8. 01:20

1.  Cookie 역직렬화

 

1) 개요

  • 쿠키에서 장바구니 데이터를 읽어와 객체로 변환하는 방식을 구현하려고 하였고 처음엔 단순한 형변환으로 데이터를 저장할 수 있다고 생각하였지만 파싱이란 개념을 몰라 문제가 발생하였다.

 

2) 문제 발생

// 처음에 생각한 방법
List<BasketItemDto> basket = (List<BasketItemDto>) basketCookie.getValue();
  • 문제 1.
    • 처음엔 단순한 형변환으로 데이터를 저장할 수 있다고 생각하였다. 하지만 여기서 ClassCastException 이라는 exception이 발생하는데 쿠키 값은 단순 문자열이기에 이를 Java 객체로 직접 변환하려고 발생하는 에러인 것을 알았다.
  • 문제 2.
    • 쿠키 값은 JSON 형식이므로 JSON 데이터를 처리하지 않으면 문자열 데이터인데 쿠키 값을 그대로 사용하려고 하면 문자열 분리와 데이터 추출을 수동으로 구현해야하고 데이터 구조가 복잡해지면 구현이 어려워진다.
  • 문제 3.
    • 위의 파싱 문제를 해결하는 코드 작성.
private List<BasketItemDto> parseBasketFromCookie(Cookie basketCookie) {
        //쿠키가 없으면 빈 장바구니로 반환
        if (basketCookie == null) {
            return new ArrayList<>();
        }
        try {
            //JSON 문자열인 쿠키 값을 List<BasketItemDto>로 역직렬화, //제네릭 타입을 처리하기 위한 도구.
            return objectMapper.readValue(decodedBasket, new TypeReference<List<BasketItemDto>>() {});

        } catch (JsonProcessingException e) {
            throw new CustomException(ErrorCode.BAD_REQUEST);
        }
    }
  • 하지만 여기서 또 다른 문제 발생하는데 바로 디코딩을 하지 않아서 JSON 파서가 %와 같은 문자를 처리하지 못해 JsonProcessingException 발생.
  • 쿠키 값과 Java의 문자열을 비교할 때, 디코딩하지 않으면 항상 불일치한다는 사실 확인.

 

3) 해결

private List<BasketItemDto> parseBasketFromCookie(Cookie basketCookie) {
        //쿠키가 없으면 빈 장바구니로 반환
        if (basketCookie == null) {
            return new ArrayList<>();
        }
        try {
            // URL 디코딩
            String decodedBasket = URLDecoder.decode(basketCookie.getValue(), "UTF-8");

            //JSON 문자열인 쿠키 값을 List<BasketItemDto>로 역직렬화, //제네릭 타입을 처리하기 위한 도구.
            return objectMapper.readValue(decodedBasket, new TypeReference<List<BasketItemDto>>() {});

        } catch (JsonProcessingException | UnsupportedEncodingException e) {
            throw new CustomException(ErrorCode.BAD_REQUEST);
        }
    }
  • String decodedBasket = URLDecoder.decode(basketCookie.getValue(), "UTF-8");
  • 위 코드를 사용하여 디코딩을 진행하였으며 디코딩을 진행함으로써.
    • URL 인코딩된 데이터를 원래의 JSON 형태로 복원
    • JSON 데이터를 안전하고 정확하게 처리.
    • 문자열 비교, JSON 파싱 등 후속 작업이 가능하도록 데이터를 가공.

 

4) 결론

  • 쿠키 데이터를 JSON에서 Java 객체로 변환함으로써 안정적으로 장바구니 데이터를 처리
  • 클라이언트와 서버 간의 데이터 통신에서 발생할 수 있는 오류를 방지

 


1.  Cookie 직렬화

 

1) 개요

  • 장바구니 데이터를 쿠키에 저장하려고 시도하였다.

2) 문제발생

  • 문제 1.
    • 직렬화를 해주지 않아서 Jav 객체를 텍스트 기반 시스템에 전달할 수 없으므로 데이터 처리가 불가능했다.
    • 데이터가 잘못된 형식으로 저장되고 시스템 간 통신이 실패.
  • 문제 2.
    • 문제 1을 해결하였지만 JsonProcessingException 이 발생하였다. 
    • 역직렬화에서 디코딩을 한 것 처럼 인코딩을 안해주어서 문제 발생.
    • JSON 데이터에 포함된 {}, =, & 등의 문자가 URL에서 해석될 수 있어 URL이 손상된다.

3) 해결

 String basketJson = objectMapper.writeValueAsString(basket);
  • Jackson 라이브러리에서 제공하는 메서드로 Java 객체를 Json 문자열로 직렬화 해준다.
String encodedBasket = URLEncoder.encode(basketJson, "UTF-8");
  • 역직렬화에서 발생한 에러와 같기 때문에 디코딩의 반대인 인코딩 필요하다는 것을 깨닫고 직렬화 Java 객체를 인코딩을 진행.
  • URLEncoder.encode(basketJson, "UTF-8")를 사용해 데이터를 퍼센트 인코딩하여 안전하게 변환.

 

  • 해결 코드
private void saveBasketToCookie(List<BasketItemDto> basket, HttpServletResponse response) {
        try {
            //List<BasketItemDto> 객체를 JSON 문자열로 직렬화
            String basketJson = objectMapper.writeValueAsString(basket);

            // URL 인코딩
            String encodedBasket = URLEncoder.encode(basketJson, "UTF-8");

            //직렬화된 JSON 데이터를 쿠키에 저장
            Cookie cookie = new Cookie("basket", encodedBasket);
            cookie.setMaxAge((int) COOKIE_MAX_AGE); // 쿠키 만료 시간 설정 (24시간)
            cookie.setHttpOnly(true); // JavaScript 접근 불가 설정
            cookie.setPath("/"); // 모든 경로에서 쿠키 접근 가능
            response.addCookie(cookie); // HTTP 응답에 쿠키 추가
        }
        catch (JsonProcessingException | UnsupportedEncodingException e ) {
            throw new CustomException(ErrorCode.BAD_REQUEST);
        }
    }

 

4) 결론

  • objectMapper.writeValueAsString은 데이터를 JSON 형식으로 변환하여 저장 및 통신 과정에서 발생할 수 있는 문제를 방지하고, 데이터의 호환성 도와줍니다.
  • URLEncoder.encode는 데이터가 URL 및 HTTP 요청에서 안전하게 사용될 수 있도록 보장하며, 클라이언트와 서버 간의 통신에서 발생할 수 있는 오류를 방지합니다.