Spring/Issue

조회수 기능 구현하기 - 중복 방지(Cookie)

블로그 주인장 2024. 1. 2.

Issue

커뮤니티 서비스를 구현하는 토이프로젝트를 진행하면서 게시판의 조회수를 증가 로직을 만드려고 합니다.

게시글이 조회될 때마다 조회수를 증가하는 게 가능하지만 

동일 사용자에 한해서 조회수가 중복이 될 수 있기 때문에 해당 조회수 중복을 어떻게 방지할 수 있을지 알아보겠습니다.

 

 

일반적인 커뮤니티의 조회수 집계 방법은?

 

네이버 블로그를 확인해보겠습니다.

 

네이버 블로그는 조회수(포스트 방문 횟수) 는 30분 이내의 재방문은 가산되지 않는다.

 

티스토리 알아보겠습니다.

 

티스토리는 방문자수와 조회수를 둘 다 제공하여 조회수를 판별할 수 있게 했다.

 

현재 구현하려는 서비스의 경우에는 블로그 개념이 아닌, 개별 글의 조회수를 제공할 예정이기에

방문자 수는 제공하지 않고, 하루 기준으로 중복 조회 기준이 리셋되도록 구현하기로 했습니다.

 

 

조회수 기능 명세

  • 하루 뒤에 동일 포스트를 읽는다면, 조회수 가산
  • 방문자 수는 미제공
  • 회원, 비회원 모두 조회수 집계 대상이다.

 

조회수 중복은 어떻게 잡아야 하나요?

첫 번째 방법은 IP or Mac Address를 사용하는 방법입니다.

 

- 접속 장소의 문제점

IP는 장소에 따라 유동적으로 변할 수 있는 문제점이 있습니다.

장점이자 단점으로 근처 여러 기기로 비회원이든 회원이든 접속해도 동일 유저로 식별될 가능성이 있습니다.

 

- Mac Address 

Mac Address 의 경우는 어느 장소에서든 식별이 가능합니다.

하지만 기기를 변경하면 다른 유저로 식별될 수 있다는 특징이 있습니다.

 

두 번째 방법으로는 Session을 이용하는 방법입니다.

 

- 성능 문제

세션사용자의 정보를 서버에서 관리하는 것입니다.

서버에서 관리하는 것은 서버의 리소스를 사용하는 것이기 때문에 서버에 부하가 커지게 됩니다.

이는 세션의 양이 방대해진다면 그만큼 서버에 부하가 발생하게 됩니다.

 

- 쿠키보다 좋은 보안

하지만 사용자 정보를 서버에 저장하기 때문에 쿠키보다는 보안이 좋습니다.

 

 

세 번째 방법으로는 Cookie를 이용하는 방법입니다.

 

- 취약한 보안

쿠키는 웹사이트에 접속할 때 생성되는 정보를 담은 임시파일입니다.

쿠기는 서버가 아닌 사용자에게 저장되는 것이기 때문에, 조작과 탈취가 쉽습니다.

이는, 임의로 고치거나 지우는 것이 가능하고, 가로채기도 쉬워서 보안에 취약합니다.

 

결론적으로

Cookie를 이용하는 방법으로 구현해볼 생각입니다.

 

그 이유는 "조회수" 자체는 민감한 정보가 포함되어 있지 않기 때문에 이 부분에 대해 걱정할 필요가 없다고 생각했고

 

"조회수"에 대한 정보가 브라우저가 종료되더라도 유지 시키기 위함에도 있습니다.

 

Cookie를 구현한 코드

해당 로직의 시퀀스는 다음과 같다

1. 프로젝트 상세 조회 API 호출 시 조회수 업데이트 진행

2. 이 때, post 이름을 가진 쿠키를 확인한다.

 - 이 때 해당 이름을 가진 ID가 있다면 조회수 가산 X

 - 쿠키가 아예 없거나, 해당 글 ID가 없다면 조회수 가산 O

3. 조회가 완료됨에 따라 response 에 값을 넣어 반환한다.

 

먼저 쿠키의 여부를 파악하는 로직을 구현해보겠습니다.

Cookie 변수를 하나 선언해서 인자로 받아온 cookies에 해당 쿠키 값에 post 라는 이름을 가진 쿠키를 받아 리턴해준다.

 

쿠키의 유무를 먼저 확인한 후에, contains 함수를 이용해서 해당 쿠키 값에 postId를 포함하고 있는지 확인한다.

 

쿠키가 없거나 현재 조회하려는 글의 ID가 없는 경우에는 새롭게 쿠키를 설정해준 후에 조회수를 업데이트 한다.

 

쿠키 설정값

  1. MaxAge : (현재 시간 기준) 쿠키를 유지할 만료기한
  2. Path : 웹 서버의 특정 URL 에서만 쿠키를 전송 가능
  3. path : Cookie 헤더를 전송하기 위하여 요청되는 URL 내에 반드시 존재해야 하는 URL 경로

 

괄호에 ID를 감싼 이유

해당 게시글을 이미 조회했는지 판단하는 함수로 contains 함수를 사용했는데, 단순히 숫자만 사용한다면 문제가 발생할 수 있다.

 

예시로, 100번 게시물을 조회하여 post 값이 100이라고 한다.

이 때, 10번 게시글을 조회하려고 하면, post 쿠키의 100에 포함되어 있는 값이기 때문에 중복된 조회로 여기고 조회수를 증가하지 않을 것이다.

 

이를 방지하기 위해 숫자를 온전히 보호하고자 [100], [10] 과 같은 방식으로 포장하여 검사 및 갱신하도록 한다.

 

문제점

사용자가 1번 게시물을 보고, 12시간 뒤에 2번 게시물을 조회한다면 쿠키의 수명이 새롭게 24시간 후로 설정이 된다.

즉, ID가 1번인 글을 조회하고, 24시간이 아닌 46시간 후에 조회수가 증가된다.

 

결론적으로 쿠키의 수명이 글을 조회할 때마다 갱신되기 때문에 죽지 않은 쿠키가 발생한다.

 

해당 링크 : https://blog.naver.com/PostView.nhn?blogId=dlaxodud2388&logNo=221917137726

 

해결방법

24시간의 제한을 포기하고, 브라우저를 닫으면 없어지는 쿠키인 세션 쿠키를 사용하기로 했다.

 

즉, 쿠키의 만료시점을 설정하지 않고 쿠키를 생성해주는 것이다.

 

 

기존 코드에서 Cookie.setMaxAge() 메서드를 제외하면 구현이 가능합니다.

 

한 줄 마무리

조회수 기능이라고 하면 단순하게 조회할 때마다 조회수를 올리면 된다고 생각했다.

조회수 조작을 방지하기 위해 중복 체크 로직이 추가적으로 들어가야한다는 것을 알았고, 이에 여러 가지 방법에 대해 찾아본 시간이 되었다. 또한, 로그인 상태가 아닌 다른 경우에도 사용자를 체크할 수 있다는 것을 깨달았다.

차후에는 조회수가 큰 서비스를 개발하며, 더 꼼꼼한 조회수 조작 방지를 위해서 어떻게 해야하는지 구현해보고 싶다.

 

 

Reference

https://ssdragon.tistory.com/118

 

https://mighty96.github.io/til/view/#ii-%EC%BF%A0%ED%82%A4%EB%A5%BC-%ED%86%B5%ED%95%9C-%EA%B5%AC%ED%98%84

 

 

 

 

 

반응형

댓글