토이 프로젝트 post page 구현기(3): 브라우저 캐싱

coolchaem·2022년 1월 11일
0

toyproject

목록 보기
8/21
post-thumbnail

다음처럼 post page에서 게시글을 view 하는 것을 계속 구현하고 있다.

구현하다가 똑같은 게시글 url을 여러번 요청하면서 왠지 저장해두고 여는게 좋지 않을까란 생각이 들었다..

평상시에도 기술 포스팅 문서나 뉴스도 한 번 볼 때 여러 게시글을 동시에 보거나,
하루동안 자꾸 똑같은 게시글을 여러번 보게 되는 경우가 많다.

일단 브라우저에 데이터 저장하는 방법은 다음 몇 가지가 있다.

브라우저에 저장되는 작은 크기의 문자열이라고 한다.
웹 서버에 의해 만들어져서 서버가 response header에 Set-Cookie 옵션을 설정하면 브라우저에 저장된다고 한다.

내용의 업데이트 시점은 사용자가 Cookie를 생성한 url에 접속할 때마다 브라우저에서 HTTP Cookie 헤더에 Cookie 내용을 같이 보낸다고 한다.

인증과 관련되어서 사용한다는 것으로 보인다.
( 세션 관리, 개인화, 트래킹 등 )
로그인 상태를 유지하는 것이 예시인 것으로 보인다.

  1. 로그인 request
    • 사용자 -(HTTP request)-> 서버
  2. 응답 OK
    • 사용자 <-(HTTP response header Set-Cookie: seesion id)- 서버
  3. 재접속
  4. 로그인 request
    • 사용자 -(HTTP request header Cookie: seesion id)-> 서버
  5. 응답 OK
    • 사용자 <-(HTTP response)- 서버

local/session storage

web storage object로 브라우저 내에 key-value pair를 저장할 수 있다. Map과 유사하게 관리된다고 한다. (setItem/getItem/removeItem과 같은 method를 제공해서란다.)

Cookie와 차이점

  • Cookie랑 다르게 네트워크 요청 시 서버로 전송되지 않는다.
  • Cookie보다 큰 데이터를 저장할 수 있다.
  • 서버가 HTTP 헤더로 storage를 수정 못 한다. web storage object 조작은 클라이언트의 javascript 내에서 수행된다.
  • domain, protocol, port로 정의되는 origin에 묶여있다고 한다.

local storage

브라우저를 다시 실행해도 데이터가 남아있는다.
origin이 같으면 모든 탭과 창에서 공유된다고 한다.
심지어 OS가 재시작해도 데이터가 파기되지 않는다는 것으로 보아, 보안과 디스크 용량에도 신경을 써야할 것으로 보인다.

음.. 사용처는 아무래도 session storage와 비슷할 것으로 보인다. 다만 브라우저가 꺼져도 계속 저장되었으면 하는 예시는...음... 장바구니 정보?
고갱님이 매일을 오래 고민하셔도 사셨으면 좋겠는데 장바구니 담은 내역을 서버는 안 되겠고 고갱님의 storage를 쓰면...나쁘지 않지 않을까..^^?

session storage

페이지를 새로 고침해도 남아있는다.
현재 떠 있는 탭 내에서만 유지된다는데.. 그래서 탭이나 브라우저를 종료하면 사라진다고 한다.

  • 같은 페이지라도 다른 탭이면 다른 곳에 저장된다고 한다.
  • 탭 내에 iframe이 여러 개일 땐 공유된다고 한다. origin 이 같아서!

생각보다 제한적이라서 local storage에 비해 자주 사용되지 않는다고 한다.

사용처는 드는 생각으로 회원가입이나 쇼핑하다가 결제페이지에서 실수로 뒤로가기 누른 날들이 생각난다... 그런데 지워져버렸을 때 너무 슬펐는데 앞으로 가기하면 저장이 되어있었는데.. 이 기능일거라는 느낌이 든다!!

회원가입했는데 가입정보를 계속 브라우저에 둘 필요가 없다! (로그인이랑 다르다)
결제페이지에서 주소 입력한 정보도 일회성이라고 생각된다(물론 서버에 최근 배송지를 저장하는건 다른 행위이다)
" 입력 중 " 일 때 특별한 이유로 잠깐 저장하고 복원하기엔 안성맞춤으로 보인다.

Cache

HTTP response 에 Cache-Control header가 있다고 한다. 리소스 (HTML, CSS, JS, image, video ... )의 생명 주기를 결정해주는 헤더라고 한다.

cache가 유효하면 재사용하고 만료되었으면 서버에 요청을 보낸다고 한다. 한 번 저장되면 만료될 때까지 캐시가 남는다.

  • max-age

    • 유효 기간으로 단위는 seconds
  • Revalidation

    • 유효 기간이 지나면 서버에 유효한지 다시 요청하여 확인
  • no-cache

    • 캐시를 저장하지만 사용할 때마다 재검증 요청
  • no-store

    • 캐시를 절대로 해서는 안 되는 리소스일 때 사용
  • public/private

    • 캐시 위치 지정 옵션
    • private이 사용자 브라우저 공간을 의미하고 public은 중간 서버를 의미

결론

브라우저 web storage object에 저장하려고 사실 알아보았다.

적용한다면 local storage에 유효기간을 1일로 하고 5개정도 적용할지에 대해 고민해보았으나,
그러나 다음 이유로 해당 내용보다 다른 내용을 알아보아야 겠다고 생각했다.

  • web stroage object는 네트워크 요청 날리기도 전에 캐싱된 것을 쓰는것인데,
    만약 게시글을 게시자가 수정했다면!?
    최신 정보가 아닌 것을 보는건 있을 수 없는 일이다.

결론적으로 private browser cache가 적합한 것 같다.
post는 항상 바뀔지 모르니 no-cache로 설정해서 캐시를 활용하면 좋을 거 같다.

일단 적용 해보기로 했다.


browser cache 적용

서버 cache-control header 설정

  • response 보내기전 header로 아래와 같이 설정해준다. 테스트 용도로 하는 것이라 유효기간은 1분으로 설정했다.
response.setHeader('Cache-Control', 'private, max-age=60');
  • 그러면 페이지를 로딩할 때 response header에 내용이 보이게 된다.

  • 그 뒤로 새로고침하면 from disk cache라는 문구를 볼 수 있다.
    • 로컬 테스트라 ms 단위이지만, 로딩 속도가 빨리진다

  • timing tab을 눌러보면 request, response 시간 잰 것이 나온다.
    • 캐시된 걸 쓰니 requset sent 필드가 0 duration time으로 나온다.

그러나 url을 서버 갱신이 되었는지 확인도 안 하고 쓰면 내용이 업데이트 되어도 확인할 수 없을 것이다.

  • no-cache 옵션 적용
response.setHeader('Cache-Control', 'private, no-cache');
  • 근데 왜 내용 변경도 없었는데 304가 아니라 200 OK status로 다 결과가 반환되었다.
    한참을 고민하다 node.js 서버 코드를 보니 status를 수동으로 200 반환하고 있었다..
    그래도 내부적으로 Etag가 같으면 304로 반환해줘야 하는 것이었다...
    • 왠지 서버 middleware library 쪽을 조사하면 나올거 같은데 서버 middleware는 아직 잘 모른다.
// res.status(code): Sets the HTTP status for the response.
      return response.status(200).json(post);
  • 그렇다면, ETag가 같은지 서버에서 확인해야하는데 express response header에 보내기도 전에 있을린 없다. 그래서 직접 만들려고 했었으나 다른 방법을 쓰기로 했다.

    • (1) 대략 포스트의 생성 시간을 이용해 hash function library 가져와서 만들어둘까했다.
      • 포스트 생성 시간은 db에 있기 때문에 url 로딩만 하면 알 수 있어서 기준으로 삼기 좋을 것으로 보았다.
    • (2) 그런데 시간이면 last-modified header 옵션을 써도 좋을 거 같았다. 포스트 수정이 짧은 시간에 이뤄지진 않을 거 같아 판단하였다.
  • 최종적으로 적용한 코드는 다음처럼 설정하였다.

    • 서버에만 코드를 추가하였고 예외처리로 넣어두었다.

response.setHeader('Cache-Control', 'private, no-cache');

if (req.headers['if-modified-since'] === new Date(post.released_at).toUTCString()) {
    return response.status(304).send();
}

response.setHeader('Last-Modified', new Date(post.released_at).toUTCString());
return response.status(200).json(post);
  • Thender client로 서버 API만 테스트했을 때 304가 나온다.

    • 근데 왜 크롬에는 200 OK로 뜰까..? 그래서 200 리턴해주는 부분 코드를 지우고 했는데 로딩은 잘 된다... 버그..? 로그 찍어도 304로 잘 넘어갔다.

    • 배포한 상태에서 테스트 한게 아니라 webpack dev server로 확인해서 그런건지, 클라이언트에서 헤더 설정이 필요한건지, 크롬 버그인지 조금 더 찾아보고 포스터를 수정하기로 하였다..

여담

실제 서비스에서 cache를 이용하여 url 로딩이나 정적 리소스를 재활용하려고 하면 어찌되었든 사용자에게 동의를 구해야할 것으로 보인다. 뭔가 저장하는거니 수집이 되는 것이니까...?
그래서 여러 사이트에 들어가면 동의를 구하는 팝업이 계속 뜨는 걸 볼 수 있다.


(22.01.25 수정)
ETag에 대해 좀 더 정리한 자료를 올려두었다.
https://velog.io/@coolchaem/HTTP-header-ETag

profile
Front-end developer

0개의 댓글