수정배포된 CSS/JS 파일 캐시 방지

웹사이트를 운영하다보면 웹사이트의 디자인이나 프론트엔드 동작을 바꾸기 위해서 CSS 또는 javascript 파일을 수정하는 일이 종종 생기게 된다. 이때 수정된 파일을 서버로 배포하더라도, 기존 웹사이트를 이용하던 유저의 브라우저 캐쉬때문에 수정된(fresh) 파일을 다운로드 하지 않고 캐쉬를 이용하게되어 웹사이트가 깨져보이게되는 경우가 있다.

사용중인 웹서버에서 특정 파일에대한 캐쉬설정을 적절히 바꿔서 Http Response Header에 캐쉬관련 지시자나 E-Tag 등이 잘 포함되게 설정해주면, 브라우저에서 expired 된 캐쉬가 사용되는 것을 적절히 막을 수 있지만, 직접 웹서버를 운영하지 않고 웹 호스팅서비스를 이용하는 경우 쉽지 않은 일이며, 정확하게 설정되지 않을경우 브라우저마다 미묘하게 동작이 달라서 원하는 결과를 완벽하게 얻지 못할때도 있다.

오래된 캐쉬(stale cache) 사용 막으려면?

이런 상황에서 캐쉬문제를 해결하기 위해서 가장 확실하고 간단한 방법은 캐쉬 자체의 기본 동작 방식을 역이용하는 것이다.

기본적으로 캐쉬의 동작은 URL을 기준으로 기존에 동일한URL에 요청한 적이 있었는지를 판단하게 된다. 쉽게 바꿔말하면, 해당 수정된 파일의 URL을 바꿔주면 기존의 캐쉬에 의해 영향을 받지 않을 수 있게 되는 것이다.

URL을 바꾸는 방법

  • 무식한 방법: 수정이 그리 자주되지 않는 파일이라면, 해당 수정된 CSS/JS 파일명을 아예 바꿔버리고, 해당 파일을 로딩하는 HTML 코드쪽에서도 수정된 파일명을 넣어주면 된다.

  • 좀더 스마트한 방법: 위 방법이 번거로울 경우 CSS/JS 파일명은 유지하는 대신 HTML 코드쪽에서 불러올때 버전 쿼리스트링을 붙여주는 방법이 매우 유용하다. 다음 예시를 살펴보자.

    위 코드의 경우 custom.css 파일이 수정되더라도, 적절한 캐쉬 지시자가 적용되지 않은경우 기존 웹사이트 이용하던 유저들이 수정된파일이 아닌 캐쉬된 파일을 보게될 확률이 크다. 이를 해결한 아래 코드를 보자.

    위 코드의 경우 ?ver=1.1 이라고 파일명 뒤에 쿼리스트링을 붙여주었다. custom.css를 수정한 후, 번거롭게 파일명을 바꾸는 대신 ver 값만 다르게 주면 다른 URL로 인식되기 때문에 캐쉬된 파일이 사용되는것을 방지할 수 있다.

    조금 더 응용한다면, server side 프로그램에서 해당 HTML 코드를 출력할때 ver 대신 해당 파일의 modified date가 자동으로 쿼리스트링으로 붙도록 개발해둘 경우, 수정되는 즉시 자동으로 반영되는 편리함을 누릴 수 있을것이다.

  • http://hackya.com Matthew

    uc6f9ud3f0ud2b8 ub85cub529uc5d0 uad00ud55c uae00uc744 uc368uc57c ud560uae4c uae00uc744 ucc3euc544ubcf4ub2e4 (ubcf4ud1b5 ub2e4ub978 ube14ub85cuadf8/ud55cuae00 uc0acuc774ud2b8uc5d0 uc774ubbf8 ubc29uc2dduc774 ud55cuae00ub85c uc18cuac1cub418uc5b4 uc788uc73cuba74 uc911ubcf5ud574uc11c uae00uc744 uc4f0uc9c0 uc54auc2b5ub2c8ub2e4.) uc5ecuae30uc11c uac00uc7a5 uc801uc808ud55c aync loading ubc29uc2dduc774 uc18cuac1c ub418uc5b4 uc788ub294uac78 ucc3euac8c ub418uc5b4 ub2e4ub978 uae00ub4e4ub3c4 uc77duc5b4 ubcf4uc558uc2b5ub2c8ub2e4.nnuad6cuae00uac80uc0c9ud574ubcf4uba74 @import rule uacfc ubb34uc2ddud558uac8c uadf8ub0e5 ub9c1ud06c uac70ub294 ubc29ubc95ub4e4ub9cc ub9ceuc774 ub098uc640 uc788uace0, uc81cub300ub85c uc6f9ud3f0ud2b8 ub85cub529ud558ub294 ubc29uc2dduc744 uc18cuac1c ud558ub294 uae00uc740 uc774uc0acuc774ud2b8 ubc16uc5d0 uc5c6ub294 uac83 uac19uc2b5ub2c8ub2e4.nnuc815ub9d0 uc720uc775ud558uace0, uc88buc740uae00ub4e4 ub9ceuc774 uc4f0uc168ub294ub370 uc694uc998uc740 uae00uc744 uc4f0uc2dcuc9c0 uc54auc73cuc2dcub294 uac83 uac19uc544 uc544uc27duc2b5ub2c8ub2e4.nnuc544, uac1cubc1cud558uc2e4ub54c ver uc774ub984 ub9e4ubc88 ubc14uafd4uc8fcuae30 ubc88uac70uc2a4ub7fduc9c0 uc54auc73cuc138uc694? uc800ub294 ubc88uac70uc2a4ub7fdub354ub77cuad6cuc694.nnuc544ud30cuce58 uc11cubc84uc2dcuba74 .htaccess uc5d0 cache-control ud55cuc904 ub123uc73cuc2dcuba74 ub9e4ubc88 ver ubc88ud638 uc548ubc14uafb8uc154ub3c4 ub418uc694. u314eu314eu314ennHeader set Cache-Control “max-age=0, no-cache, no-store, must-revalidate”nnNginx uba74 add_header Cache-Control ud558uba74ub418uace0.nnuadf8ub9acuace0 uc6f9ud3f0ud2b8uae00uc5d0 FOUT ud604uc0c1 uc8fcuc758ud574uc57c ud55cub2e4uace0 ud558uc168ub358ub370, sessionStorage.fonts = true; ub85c ud574ub193uc73cuc2dcuba74 FOUT ud604uc0c1uc774 ubc29uc9c0ub429ub2c8ub2e4. (ubaa8ubc14uc77c uc5d0uc11cub294 FOUT ub300uc751uc744 ud574uc918uc57c ud558uac70ub4e0uc694.)nnuc544!!! uc81cuac00 uc774 ubd80ubd84uc744 ubabb ubd24ub124uc694. u314bu314bu314bnn”uc0acuc6a9uc911uc778 uc6f9uc11cubc84uc5d0uc11c ud2b9uc815 ud30cuc77cuc5d0ub300ud55c uce90uc26cuc124uc815uc744 uc801uc808ud788 ubc14uafd4uc11c Http Response Headeruc5d0 uce90uc26cuad00ub828 uc9c0uc2dcuc790ub098 E-Tag ub4f1uc774 uc798 ud3ecud568ub418uac8c uc124uc815ud574uc8fcuba74, ube0cub77cuc6b0uc800uc5d0uc11c expired ub41c uce90uc26cuac00 uc0acuc6a9ub418ub294 uac83uc744 uc801uc808ud788 ub9c9uc744 uc218 uc788uc9c0ub9cc,”nnubcf4ud1b5 uc5b4ub290 uc6f9ud638uc2a4ud305uc774ub098 .htaccess ud30cuc77cuc744 access ud560 uc218 uc788uc9c0ub9cc, uc774uac8c ubd88uac00ub2a5ud55c uacbduc6b0, ubb38uc11cuc5d0 meta ub97c ud558ub098 ub123uc5b4uc8fcub294 ubc29ubc95ub3c4 uc788uc2b5ub2c8ub2e4.n

  • http://www.letmecompile.com/ YoungJae Kwon

    uc694uc998 ub108ubb34 ubc14ube60uc11c uae00uc744 ub0a8uae38 uc2dcuac04uc774 uc5c6ub124uc694 u314eu314e cache-controluc744 uc368uc11c uce90uc2dcub97c uc548ud558uac8cub420uacbduc6b0 uc0acuc6a9uc790uac00 uce90uc26cub41c cssub97c uc0acuc6a9ud558uc9c0 ubabbud558uace0 ub9e4ubc88 cssud30cuc77cuc744 uc0c8ub85c ubc1buc544uc57c ud574uc11c uadf8ub807uac8c uc88buc740 ubc29ubc95uc740 uc544ub2d9ub2c8ub2e4. uc800ub294 css ud30cuc77cuc758 uc218uc815uc2dcuac01uc758 ud0c0uc784uc2a4ud0ecud504ub97c uac00uc838uc640uc11c ver=”modifiedTimeStamp” uac19uc740 uc2dduc73cub85c ubd99uc5ecuc11c uc790ub3d9ud654uc2dcucf1cuc11c uc0acuc6a9uc911uc785ub2c8ub2e4. uc774ub807uac8cud558uba74 ud574ub2f9 cssuac00 uc218uc815ub420ub54c uc790ub3d9uc73cub85c ver uac00 ubcc0uacbdub429ub2c8ub2e4.

  • 박영식

    자주 업데이트되는 사이트는 아닌데, 캐시 삭제 후 재시도를 할 필요 없게 할 때 유용하군요. js 파일도 잘 되네요.

    감사합니다.