<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>F개발자의 에러로그</title>
    <link>https://f-dever-error-log.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sun, 9 Aug 2026 16:27:44 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>보오</managingEditor>
    <item>
      <title>Javascript - 호이스팅에 관하여</title>
      <link>https://f-dever-error-log.tistory.com/67</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;자바스크립트에서 함수 호이스팅이란?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수를 먼저 실행시키고 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;함수선언문(Function Declarations)&lt;/u&gt;&lt;/span&gt;을 나중에 작성해도 자바스크립트에서 해당 함수를 실행시킬 수 있는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;함수선언문(Function Declarations) - fucntion MyFunc(){} 형태의 함수 선언문&lt;br /&gt;함수표현식(Function Expressions) - 변수에 함수를 할당하는 방식(JS의 유연한 특성)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; JS 컴파일 시점에 나중에 선언된 함수에 대한 메모리를 할당해놓은 상태이기 때문에, &lt;b&gt;실행 시점에 선언된 함수의 식별자 정보를 이미 알고 있음&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정확히 말하면 자바스크립트는 함수만 호이스팅 할 수 있는게 아니라 변수까지 호이스팅 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 전에 자바스크립트가 변수를 할당하는 과정을 알아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-token-index=&quot;0&quot; data-reactroot=&quot;&quot;&gt;자바스크립트가 변수를 할당할 때 &amp;lt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;선언 &amp;rarr; 초기화 &amp;rarr; 할당&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&amp;gt;의 과정을 거친다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;선언&lt;/b&gt;: 파싱 과정에서 변수 객체가 변수에 대한 식별자들을 수집하는 일&lt;br /&gt;&lt;b&gt;*초기화&lt;/b&gt;: 식별자에 메모리를 할당하고&amp;nbsp;undefined&amp;nbsp;상태를 부여함&lt;br /&gt;&lt;b&gt;할당&lt;/b&gt;: 변수 안에 직접 값을 넘겨줌&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 과정에 의해 var, let, const 호이스팅에 차이점이 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선언된 함수는 상단에서 참조, &lt;b&gt;호출&lt;/b&gt;이 가능하다.&lt;/li&gt;
&lt;li&gt;선언된 var는 상단에서 참조, &lt;b&gt;할당&lt;/b&gt;이 가능하다.&lt;/li&gt;
&lt;li&gt;선언된 let, const는 상단에서 참조, 할당이 불가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  &lt;span style=&quot;background-color: #f6e199;&quot;&gt;왜 var는 되고 let, const는 안되나?&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수가 할당되기까지는 선언/초기화/할당의 3가지 단계를 거침&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;var&lt;/b&gt;는 호이스팅이 발생하면 선언과 &lt;u&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot; data-token-index=&quot;1&quot; data-reactroot=&quot;&quot;&gt;초기화&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot; data-token-index=&quot;2&quot; data-reactroot=&quot;&quot;&gt;가 거의 동시에 이루어져서&lt;/span&gt;&lt;/u&gt; 실행 시점에 스코프 최상단에서 해당 변수에 대한 메모리가 살아있기 때문에 참조, 할당이 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;let, const&lt;/b&gt;는 호이스팅이 발생 시 선언만 이루어지기 때문에 &lt;u&gt;&lt;i&gt;&lt;span style=&quot;color: #000000;&quot; data-token-index=&quot;4&quot; data-reactroot=&quot;&quot;&gt;선언부를 만나기 전 까지는 초기화가 이루어지지 않은&lt;/span&gt;&lt;/i&gt;&lt;/u&gt; 상태. 따라서 해당 변수에 대한 메모리가 존재하지 않기 때문에 선언하기전에는 참조, 할당이 불가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;** let, const 선언문 전에 호출하는 경우 &amp;rArr; &lt;span style=&quot;color: #333333;&quot;&gt;&lt;i&gt;참조에러&lt;/i&gt;&lt;/span&gt; 발생&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1176&quot; data-origin-height=&quot;160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xmqnP/btrAVr9BCOf/uabEbeU3X7YavKRLzlPip1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xmqnP/btrAVr9BCOf/uabEbeU3X7YavKRLzlPip1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xmqnP/btrAVr9BCOf/uabEbeU3X7YavKRLzlPip1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxmqnP%2FbtrAVr9BCOf%2FuabEbeU3X7YavKRLzlPip1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;540&quot; height=&quot;73&quot; data-origin-width=&quot;1176&quot; data-origin-height=&quot;160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 let 또는 const로 선언한 함수표현식을 상단에서 사용하려고 하면 초기화 하기 전에 접근할 수 없다는 &lt;u&gt;&lt;i&gt;&lt;b&gt;ReferenceError&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;가 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 위 현상을 &lt;b&gt;&lt;i&gt;TDZ(Temporal Dead Zone),&lt;/i&gt;&lt;/b&gt; 일시적 사각지대라고 한다. &lt;i&gt;변수는 존재하지만 초기화되어 있지 않은 상태&lt;/i&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;** var에 함수를 할당하고 나중에 호출하는 경우 &amp;rArr;&lt;i&gt; 타입에러&lt;/i&gt; 발생&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;164&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l8bjA/btrAUx3i2qA/kYqiWVdRKKSvkbRwz4glo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l8bjA/btrAUx3i2qA/kYqiWVdRKKSvkbRwz4glo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l8bjA/btrAUx3i2qA/kYqiWVdRKKSvkbRwz4glo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl8bjA%2FbtrAUx3i2qA%2FkYqiWVdRKKSvkbRwz4glo1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;360&quot; height=&quot;164&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;164&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var 변수 sayHi는 참조는 가능하지만, &lt;u&gt;초기화만 이루어지고 함수가 할당이 되지 않은 상태&lt;/u&gt;이기 때문에 &lt;b&gt;&lt;u&gt;&lt;i&gt;TypeError&lt;/i&gt;&lt;/u&gt;&lt;/b&gt;가 발생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;참조에러(Reference Error): &lt;/b&gt;엔진이 스코프에서 대상을 찾을 수 없을 때 발생. ex) 선언되지 않은 변수를 사용하려고 할 때, 없는 변수를 사용하려고 할 때&lt;br /&gt;&lt;b&gt;타입에러(Type Error): &lt;/b&gt;엔진이 스코프 검색은 성공했으나, 대상을 가지고 불가능한 시도를 하였을 경우. ex) 함수가 아닌데 함수처럼 사용하려고 했을 때, iterable이 아닌데 iterator로 순회하려고 했을 때&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 문서:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://poiemaweb.com/es6-arrow-function&quot;&gt;Arrow function | PoiemaWeb&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@exploit017/JS-ReferenceError-TypeError&quot;&gt;[JS] ReferenceError / TypeError&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://joshua1988.github.io/web-development/javascript/function-expressions-vs-declarations/&quot;&gt;함수 표현식 vs 함수 선언식&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tecoble.techcourse.co.kr/post/2021-04-25-hoisting/&quot;&gt;호이스팅에 대한 오해와 진실&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://oowgnoj.dev/review/advanced-js-1&quot;&gt;JavaScript, 인터프리터 언어일까?&lt;/a&gt;&lt;/p&gt;</description>
      <category>Javascript</category>
      <category>const</category>
      <category>javascript</category>
      <category>Let</category>
      <category>var</category>
      <category>함수선언식</category>
      <category>함수표현식</category>
      <category>함수호이스팅</category>
      <category>호이스팅</category>
      <author>보오</author>
      <guid isPermaLink="true">https://f-dever-error-log.tistory.com/67</guid>
      <comments>https://f-dever-error-log.tistory.com/67#entry67comment</comments>
      <pubDate>Sun, 1 May 2022 14:13:30 +0900</pubDate>
    </item>
    <item>
      <title>useSWR, 그리고 stale-while-revalidate</title>
      <link>https://f-dever-error-log.tistory.com/66</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;노션으로 깔끔하게 보기: &lt;a href=&quot;https://glistening-seashore-ed4.notion.site/useSWR-stale-while-revalidate-0e829551bc624b338b9bcfae97faa4a1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://glistening-seashore-ed4.notion.site/useSWR-stale-while-revalidate-0e829551bc624b338b9bcfae97faa4a1&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1649782513420&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;useSWR, 그리고 stale-while-revalidate&quot; data-og-description=&quot;useSWR을 사용하는 이유: 전역 상태관리를 위해 + 캐시를 효과적으로 사용하기 위해&quot; data-og-host=&quot;glistening-seashore-ed4.notion.site&quot; data-og-source-url=&quot;https://glistening-seashore-ed4.notion.site/useSWR-stale-while-revalidate-0e829551bc624b338b9bcfae97faa4a1&quot; data-og-url=&quot;https://glistening-seashore-ed4.notion.site/0e829551bc624b338b9bcfae97faa4a1&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://glistening-seashore-ed4.notion.site/useSWR-stale-while-revalidate-0e829551bc624b338b9bcfae97faa4a1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://glistening-seashore-ed4.notion.site/useSWR-stale-while-revalidate-0e829551bc624b338b9bcfae97faa4a1&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;useSWR, 그리고 stale-while-revalidate&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;useSWR을 사용하는 이유: 전역 상태관리를 위해 + 캐시를 효과적으로 사용하기 위해&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;glistening-seashore-ed4.notion.site&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;uswSWR.png&quot; data-origin-width=&quot;297&quot; data-origin-height=&quot;170&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UiO42/btrzgiMrdYg/mmXTtgPj3cuX1gVyLxF8D0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UiO42/btrzgiMrdYg/mmXTtgPj3cuX1gVyLxF8D0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UiO42/btrzgiMrdYg/mmXTtgPj3cuX1gVyLxF8D0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUiO42%2FbtrzgiMrdYg%2FmmXTtgPj3cuX1gVyLxF8D0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;297&quot; height=&quot;170&quot; data-filename=&quot;uswSWR.png&quot; data-origin-width=&quot;297&quot; data-origin-height=&quot;170&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useSWR을 사용하는 이유: 전역 상태관리를 위해 + 캐시를 효과적으로 사용하기 위해&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;잠깐, SWR이 뭔데?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식문서에도 나와있지만, 다들 눈에서 자동으로 필터링 했을 것이므로 한번 더 언급하자면 useSWR에서 SWR은 &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;stale-while-revalidate&lt;/b&gt;&lt;/span&gt;의 약자이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;stale-while-revalidate&lt;/b&gt;&lt;/span&gt;란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc5861&quot;&gt;RFC 5861&lt;/a&gt;에서 정의된 용어로, 캐시가 가지고 있는 stale response가 유효한 지 백그라운드에서 재검증하는 동안 해당 stale response를 즉시 리턴하여 네트워크 지연 시간을 숨기는 전략&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stale response? 최신이 아닌 낡은 데이터&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  stale(사전적 의미): &lt;span style=&quot;color: #f89009;&quot;&gt;신선하지 않은, 낡은, 썩은&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉬운 예시)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 유통기한: max-age&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 실제 음식이 상했는지? stale-while-revalidate&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rArr; 유통기한 지났다고 음식을 못먹나? 그건 No No.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배민 예시)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나에게 보이는 화면은 &amp;ldquo;접수 전&quot;인데 실제 사장님은 이미 접수를 했음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;response가 전달되기 전에는 &amp;ldquo;접수 전&quot;이라는 데이터는 stale한 상태&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 response가 와서 상태를 업데이트 시켜주기 전까지는 client에서는 이러한 stale 데이터가 존재하기 마련.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;캐시컨트롤 예시)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;Cache-Control: max-age=600, stale-while-revalidate=30&lt;/span&gt;&lt;/b&gt; (캐시 유효기간은 5분, stale 기간은 30초로 설정한 상태)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;nbsp;600초&amp;nbsp;내에서는&amp;nbsp;이&amp;nbsp;데이터는&amp;nbsp;유효하다&amp;nbsp;&amp;rarr;&amp;nbsp;계속&amp;nbsp;캐시에서&amp;nbsp;가져온다.&amp;nbsp;(새로&amp;nbsp;요청&amp;nbsp;X)&lt;br /&gt;-&amp;nbsp;600초가&amp;nbsp;지난&amp;nbsp;후&amp;nbsp;610초가&amp;nbsp;되었다면?&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;이미&amp;nbsp;낡은&amp;nbsp;데이터.&amp;nbsp;&amp;ldquo;stale&amp;rdquo;한&amp;nbsp;데이터로&amp;nbsp;취급.&amp;nbsp;일반적으로는&amp;nbsp;loader가&amp;nbsp;돌면서&amp;nbsp;API을&amp;nbsp;다시&amp;nbsp;호출해야함.&lt;br /&gt;-&amp;nbsp;만약&amp;nbsp;stale-while-revalidate가&amp;nbsp;설정되어&amp;nbsp;있다면?&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;&amp;ldquo;캐시&amp;nbsp;유효기간이&amp;nbsp;지난&amp;nbsp;후에도&amp;nbsp;설정한&amp;nbsp;시간동안은&amp;nbsp;만료된(stale한&amp;nbsp;상태의)&amp;nbsp;캐시데이터를&amp;nbsp;받아오겠다&amp;rdquo;는&amp;nbsp;뜻&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;rarr;&amp;nbsp;610초에&amp;nbsp;조회&amp;nbsp;시&amp;nbsp;로더가&amp;nbsp;아닌&amp;nbsp;낡은&amp;nbsp;데이터를&amp;nbsp;일단&amp;nbsp;보여줌.&amp;nbsp;그동안&amp;nbsp;refetch가&amp;nbsp;진행되고&amp;nbsp;response가&amp;nbsp;오면&amp;nbsp;상태가&amp;nbsp;반영&amp;nbsp;됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그래서 stale-while-revalidate가 왜 좋은건데?&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- latency가 숨겨짐: refetching 동안 loader을 보여줘야 하는 불필요한 UI 변경을 막음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 좀 더 유연하게 캐시데이터를 활용할 수 있음: 만료되었다고 무조건 끝이 아니다!! &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;i&gt;(유통기한 지났다고 못먹는 음식이냐!!)&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;(출처: &lt;a href=&quot;https://www.youtube.com/watch?v=MArE6Hy371c&quot;&gt;[LIVE] React Query와 상태관리 :: 2월 우아한테크세미나&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 컨셉을 적용한 것이 react-query, useSWR 등의 라이브러리다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;useSWR을 사용하는 가장 큰 이유&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 가지 이유가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나는 &amp;ldquo;&lt;b&gt;상태관리를 전역으로 하기 위해&amp;rdquo;,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째는 위에서 언급한 &lt;b&gt;&amp;ldquo;캐시를 효과적으로 사용하기 위해&amp;rdquo;&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고 보면 두 개가 연결된 것인데, 첫번째부터 설명하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;상태관리를 전역으로 하는 것이 뭔가요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트와 같은 프레임워크에서 변할 수 있는 값이라면 모두 &amp;ldquo;상태&amp;rdquo;라고 지칭한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 상태는 기본적으로 컴포넌트 단위로 관리가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 유저정보를 보여주는 &amp;lt;UserProfile/&amp;gt;이라는 컴포넌트가 있고 해당 컴포넌트가 userInfo의 상태를 갖는다고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;UserProfile/&amp;gt; 컴포넌트는 대략 이렇게 생겼을 것이다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const UserProfile = async() =&amp;gt; {

	const { data: userInfo } = await axios('/user/me');

	return(
		&amp;lt;ul&amp;gt;
			&amp;lt;li&amp;gt;{userInfo.name}&amp;lt;/li&amp;gt;
			&amp;lt;li&amp;gt;{userInfo.email}&amp;lt;/li&amp;gt;
			&amp;lt;li&amp;gt;{userInfo.regDate}&amp;lt;/li&amp;gt;
		&amp;lt;/ul&amp;gt;
	)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;userInfo는 비동기로 /user/me 라는 API를 통해 가져오는 데이터다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 개발하다보면 이 유저정보 데이터가 이 &amp;lt;UserProfile/&amp;gt; 컴포넌트에서만 쓰일리가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 유저정보를 주문정보를 보여주는 &amp;lt;OrderInfo/&amp;gt;라는 컴포넌트에서도 보여준다고 가정해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, &amp;lt;OrderInfo/&amp;gt; 컴포넌트에서 userInfo을 얻는 방법은 두 가지가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;1. ajax로 API에서 가져오기&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;2. UserProfile에서 사용하는 userInfo을 &amp;lt;UserProfile/&amp;gt;, &amp;lt;OrderInfo/&amp;gt; 둘 다 품고 있는 부모컴포넌트로 옮기고 부모컴포넌트에서 props로 상속받기&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 방법 다 비효율적이다. 1번은 같은 API을 중복으로 호출하는 문제가 있고, 2번은 &amp;lt;UserProfile/&amp;gt;, &amp;lt;OrderInfo/&amp;gt; 모두를 품고있는 부모를 찾아 상위 컴포넌트를 거슬러 올라가야 한다. (만약 교집합이 없다면 &amp;lt;App/&amp;gt;까지 올라갈 것이다..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 비효율을 해결하기 위해 나온 것이 아직도 널리 쓰이고 있는 &lt;b&gt;redux&lt;/b&gt; 상태관리 라이브러리다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 컴포넌트에서 필요한 상태를 전역으로 관리하여 컴포넌트에서 독립적으로 쓸 수 있도록 부모자식 상관없이 아무 컴포넌트에서나 막 꺼내 쓸 수 있도록 만든 것이 redux이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 redux는 훌륭한 취지와는 다르게 사용하다보면 마냥 아릅답지만은 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;store을 만들고, store을 업데이트 할 수 있는 액션을 정의하고, 액션을 실행하는 reducer을 만들고.. 러닝커브도 러닝커브지만, 세팅하는데 필요한 boiler-plate가 많아진다. 한가지 상태관리를 위해 코드를 최소 30줄은 짜야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비효율을 해결하기 위해 나온 기술이 더 비효율 적인 상황이 발생한 것.&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt; &lt;s&gt;개발자는 언제나 비효율적인 것을 못참지. 특히 프론트개발자는 더더욱.&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;s&gt;&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 나온 것이 react-query, useSWR 등의 새로운 상태관리 라이브러리다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구구절절한 화려하기만 한 boiler-plate 필요없이, 한줄이면 아주 간편하게 상태관리를 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;haskell&quot;&gt;&lt;code&gt;const { data } = useSWR(key);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;네? 이걸로 전역 상태관리가 가능하다구요?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;넵. 왜냐면 uswSWR은 여러 컴포넌트에서 데이터를 호출해도 내부적으로 캐시하여 상태를 &amp;lsquo;기억'하고 있거든요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 &amp;lt;UserProfile/&amp;gt;, &amp;lt;OrderInfo/&amp;gt; 컴포넌트를 예시로 들자면 이렇게 쓸 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const UserProfile = () =&amp;gt; {

	const { data: userInfo } = useSWR('/user/me');

	return(
		&amp;lt;ul&amp;gt;
			&amp;lt;li&amp;gt;{userInfo.name}&amp;lt;/li&amp;gt;
			&amp;lt;li&amp;gt;{userInfo.email}&amp;lt;/li&amp;gt;
			&amp;lt;li&amp;gt;{userInfo.regDate}&amp;lt;/li&amp;gt;
		&amp;lt;/ul&amp;gt;
	)
}

// OrderList은 유저의 주문정보가 담긴 컴포넌트임.
const OrderInfo = () =&amp;gt; {

	const { data: userInfo } = useSWR('/user/me');

	return(
		&amp;lt;div&amp;gt;
			&amp;lt;div&amp;gt;{userInfo.email}&amp;lt;/div&amp;gt;
			&amp;lt;OrderList/&amp;gt;
		&amp;lt;/div&amp;gt;
	)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 처음 보면 &amp;ldquo;어? /user/me가 두번 호출되는거 아니야?&amp;rdquo;라고 생각할 수 있지만, useSWR에서 내장된 캐시로 데이터를 처리하기 때문에 실제로 요청은 1번만 가게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의심이 된다면 당장 네트워크 탭을 열어 확인해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 필자가 만들고 있는 앱에서는 useSWR을 사용해 유저정보를 가져오는 부분이 있는데, 총 29개의 컴포넌트에서 사용하고 있으나(헤더, 푸터, 등등) 요청은 단 한번만 간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 useSWR의 첫번째 인자로 받는 string 값(&amp;mdash; api_enpoint가 들어가는 자리)을 key라고 부르는데, 이 key가 같을 경우 uswSWR에서 같은 데이터라고 보고 상태를 공유하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시에서는 key가 &amp;lsquo;/user/me&amp;rsquo;로 같으니 컴포넌트가 달라도 상태가 전역으로 공유되어 한번만 요청하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 앞서 언급한 두 가지 문제 &amp;mdash; API 중복 호출, 부모 컴포넌트로부터 props을 내려받아야 하는 문제가 한번에 해결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redux보다 훨씬 쉽고 간편하다. &lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;&lt;s&gt;(리덕스 이해하는데 2달 걸림...)&lt;/s&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 장점때문에 리덕스의 대안으로 급부상하여 useSWR 지분이 점점 커지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지가 첫번째 이유고, 두번째 이유는 &amp;ldquo;캐시를 효과적으로 사용하기 위해&quot;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://swr.vercel.app/ko/docs/options&quot;&gt;공식문서&lt;/a&gt;를 보면 알겠지만, useSWR은 데이터 캐시에 대한 아주 다양한 옵션들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 옵션을 통해 처음에 언급한 stale 시간, cache 시간을 설정할 수 있으며 dedupingInterval, revalidateIfStale 등을 지정하여 유연하게 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 mutate를 사용해 데이터를 즉각적으로 갱신 또는 API Response가 오기 전에 미리 갱신할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째 이유는 글이 너무 길어질 것 같으므로 useSWR 사용법과 함께 자세히 설명하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;useSWR 사용법은 다음 포스팅으로..&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;mdash; Reference&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://jbee.io/react/thinking-about-global-state/&quot;&gt;전역 상태 관리에 대한 단상 (stale-while-revalidate)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@familyman80/%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%A0%84%EC%97%AD%EA%B4%80%EB%A6%AC-redux-%EB%A7%90%EA%B3%A0-%ED%8E%B8%ED%95%98%EA%B2%8C-SWR-%EB%A1%9C&quot;&gt;비동기 전역관리 redux 말고 편하게 SWR 로!&lt;/a&gt;&lt;/p&gt;</description>
      <category>리액트</category>
      <category>stale-while-revalidate</category>
      <category>swr</category>
      <category>useSWR</category>
      <category>리액트 상태관리</category>
      <category>캐시컨트롤</category>
      <author>보오</author>
      <guid isPermaLink="true">https://f-dever-error-log.tistory.com/66</guid>
      <comments>https://f-dever-error-log.tistory.com/66#entry66comment</comments>
      <pubDate>Wed, 13 Apr 2022 02:06:03 +0900</pubDate>
    </item>
    <item>
      <title>[Cloudflare 시리즈3] 클라우드플레어 사이트최적화 - 스피드</title>
      <link>https://f-dever-error-log.tistory.com/65</link>
      <description>&lt;table style=&quot;border-collapse: collapse; width: 66.9767%; height: 108px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://f-dever-error-log.tistory.com/63&quot;&gt;1. 클라우드플레어 작동원리&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://f-dever-error-log.tistory.com/64&quot;&gt;2. 클라우드플레어 사이트 최적화 - 캐싱&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://f-dever-error-log.tistory.com/65&quot;&gt;3. 클라우드플레어 사이트 최적화 - 스피드&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드플레어 스피드 메뉴에서는 사이트의 속도를 분석해주면서 다양한 최적화 서비스를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;클플Speed개요.png&quot; data-origin-width=&quot;2834&quot; data-origin-height=&quot;1282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVDhaF/btryU1SVHIN/8cED3qjUMszpsH3L38tq01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVDhaF/btryU1SVHIN/8cED3qjUMszpsH3L38tq01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVDhaF/btryU1SVHIN/8cED3qjUMszpsH3L38tq01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVDhaF%2FbtryU1SVHIN%2F8cED3qjUMszpsH3L38tq01%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2834&quot; height=&quot;1282&quot; data-filename=&quot;클플Speed개요.png&quot; data-origin-width=&quot;2834&quot; data-origin-height=&quot;1282&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Speed 개요 탭에서는 속도 분석 결과를 제공하는데 자세히 보면 기준이 South Carolina, USA다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 미국 기준으로 1.1초 후에 페이지 로딩이 시작된다는 뜻으로 우리나라의 기준과 다소 맞지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분은 그냥 패스하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #7a869a;&quot;&gt;(구글 개발자도구로도 충분히 분석이 가능하니..)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최적화 탭을 보면 속도 개선을 위한 다양한 옵션이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 크기 조정, Polish, 자동최소화, Brotli, URL 프리패치, 로켓 로더 등 엄청 많지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;대부분이 유료이고 무료로 쓸 만한 것들로는 자동최소화와 로켓로더가 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 이 두개만 적용해도 충분히 속도가 향상된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;id-[Cloudflare]3.사이트최적화-스피드-1.자동최소화(AutoMinify)&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 자동최소화(Auto Minify)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;클플자동최소화.png&quot; data-origin-width=&quot;2080&quot; data-origin-height=&quot;510&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D5OXo/btryUfcPmgG/inUAitgtZJVaGmVYtqa3Lk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D5OXo/btryUfcPmgG/inUAitgtZJVaGmVYtqa3Lk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D5OXo/btryUfcPmgG/inUAitgtZJVaGmVYtqa3Lk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD5OXo%2FbtryUfcPmgG%2FinUAitgtZJVaGmVYtqa3Lk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2080&quot; height=&quot;510&quot; data-filename=&quot;클플자동최소화.png&quot; data-origin-width=&quot;2080&quot; data-origin-height=&quot;510&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Minify를 하면 모든&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;주석과 공백이 제거&lt;/b&gt;되고 코드가 한 줄로 줄어들어 용량을 최소화 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 언어마다 미니파이 모듈도 있고 VSC 익스텐션도 있어서 직접 해줄 수도 있지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드플레어를 사용한다면 Auto Minify 설정으로 한번에 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사진처럼 체크 해준 뒤 캐시 Purge(삭제)를 하면 바로 적용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;minify적용탭.png&quot; data-origin-width=&quot;707&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8wZO6/btryU1yDbwI/EfXW7CBMoQKQDpAFaJX0VK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8wZO6/btryU1yDbwI/EfXW7CBMoQKQDpAFaJX0VK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8wZO6/btryU1yDbwI/EfXW7CBMoQKQDpAFaJX0VK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8wZO6%2FbtryU1yDbwI%2FEfXW7CBMoQKQDpAFaJX0VK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;707&quot; height=&quot;134&quot; data-filename=&quot;minify적용탭.png&quot; data-origin-width=&quot;707&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*** 응답 헤더의 &lt;b&gt;cf-bgj: minify&lt;/b&gt; 설정은 클플을 통한 Auto minify가 되어있다는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;minify_code.png&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;162&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r0hFA/btry0dq5EP8/FHrMVIB5s3797TEaT5L5f0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r0hFA/btry0dq5EP8/FHrMVIB5s3797TEaT5L5f0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r0hFA/btry0dq5EP8/FHrMVIB5s3797TEaT5L5f0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr0hFA%2Fbtry0dq5EP8%2FFHrMVIB5s3797TEaT5L5f0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;734&quot; height=&quot;162&quot; data-filename=&quot;minify_code.png&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;162&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;minify가 적용된 파일은 Response 탭을 통해 확인할 수 있는데 띄어쓰기, 줄바꿈 없이 코드가 깔끔하게 한줄로 바뀌어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;id-[Cloudflare]3.사이트최적화-스피드-2.로켓로더(RocketLoader)켜기&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 로켓 로더(Rocket Loader) 켜기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지 로딩 시간을 지연시키는 요소 중 하나가 브라우저의 렌더링 차단이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 브라우저는 html을 읽고 해석하여(이하 &quot;파싱&quot;) 화면을 만드는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간에 css나 js를 만나면 파싱을 중단하고 css, js를 먼저 읽는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 중간중간에 css나 js가 많이 끼어있을 수록 페이지 전체를 읽는 시간이 지연된다는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 보통은 css은 &amp;lt;head&amp;gt;영역에 넣고 js는 &amp;lt;/body&amp;gt;태그 바로 직전에 넣을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 다른 이유로 중간에 js를 끼워넣는 경우도 있는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;js를 읽기 위해 html 파싱을 잠시 멈추는 것을 렌더링 차단이라고 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것을 방지하기 위해 클라우드플레어에서 로켓로더라는 서비스를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;클플로켓로더설정.png&quot; data-origin-width=&quot;2066&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vcDjS/btryYn8Nx7U/kk1r6Ycjpf1FT4JSQyOjc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vcDjS/btryYn8Nx7U/kk1r6Ycjpf1FT4JSQyOjc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vcDjS/btryYn8Nx7U/kk1r6Ycjpf1FT4JSQyOjc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvcDjS%2FbtryYn8Nx7U%2Fkk1r6Ycjpf1FT4JSQyOjc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2066&quot; height=&quot;424&quot; data-filename=&quot;클플로켓로더설정.png&quot; data-origin-width=&quot;2066&quot; data-origin-height=&quot;424&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Speed&amp;gt;최적화&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;탭에서 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로켓 로더가 하는 일은 이 렌더링 차단을 막는 일로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자바스크립트 로드를 지연시켜 페이지의 모든 컨텐츠(텍스트, 이미지, 글꼴 등)가 로드된 이후 자바스크립트를 읽도록&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;js에 defer속성과 비슷하다고 보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #7a869a;&quot;&gt;(&lt;a href=&quot;https://blog.asamaru.net/2017/05/04/script-async-defer/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://blog.asamaru.net/2017/05/04/script-async-defer/&lt;/a&gt;&amp;nbsp;참고)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;id-[Cloudflare]3.사이트최적화-스피드-특정파일로켓로더제외하려면?&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;특정 파일 로켓 로더 제외하려면?&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로켓로더를 섣불리 켰다가 문제가 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;**&lt;b&gt;스크립트가 실행되어야만 렌더링할 수 있는 페이지의 경우&lt;/b&gt;(무조건 js를 먼저 읽어야 하는 경우)는 로켓로더 설정을 꺼줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 때 제외할 스크립트 태그에 &quot;&lt;b&gt;data-cfasync=false&lt;/b&gt;&quot; 속성을 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-hasbody=&quot;true&quot; data-macro-name=&quot;code&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;highlighter_446509&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 클라우드플레어 로켓로더 설정 제외할 스크립트
&amp;lt;script data-cfasync = &quot;false&quot; src = &quot;/ javascript.js&quot;&amp;gt; &amp;lt;/ script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;202020702_클라우드플레어_render-blocking-resources.png&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;269&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWKOGY/btryZILkoSQ/Myd0bDu4yECKKtiQeZsGsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWKOGY/btryZILkoSQ/Myd0bDu4yECKKtiQeZsGsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWKOGY/btryZILkoSQ/Myd0bDu4yECKKtiQeZsGsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWKOGY%2FbtryZILkoSQ%2FMyd0bDu4yECKKtiQeZsGsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;733&quot; height=&quot;269&quot; data-filename=&quot;202020702_클라우드플레어_render-blocking-resources.png&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;269&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로켓로더를 키고 개발자도구 Lighthouse로 사이트 성능을 측정해보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Eliminate render-blocking resources 시간이 확연히 줄어든 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;id-[Cloudflare]3.사이트최적화-스피드-3.정리하면서..&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 정리하면서..&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹사이트의 성능은 매우매우 중요하다. &lt;span&gt;정신없이 개발하다보면 꼭 성능 이슈가 발생하는데,&lt;/span&gt;&amp;nbsp;사이트 성능은&lt;b&gt;&amp;nbsp;SEO와도 직결&lt;/b&gt;되어 사이트 유입에 막대한 영향을 끼치므로 시간을 내서 투자해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘엔 브라우저 성능이 워낙 좋아져서 거기서 거기라고 생각할 수 있지만, 메모리누수, 불필요한 로직이 쌓이고 쌓이다보면 웹을 점점 느리게 만든다. 그런 면에서 클플은 개발자가 일일이 설정해줘야 할 작업을 알아서 해주기 때문에 매우 편하고 강력한 서비스라고 할 수 있다. (물론 그 전에 코드로 할 수 있는 최적화 작업은 모두 해놓는 것이 기본)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;클라우드플레어가 좋대&quot;라는 말만 듣고 단순히 등록만 해놓는 것 보다, 네트워크 구조와 클라우드플레어의 작동원리를 알고 자기 사이트에 맞게 설정한다면 클플을 120% 활용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클플은 세계 1위 CDN 기업인 만큼 이 시리즈에서 설명한 것 보다 훨씬 많은 기능들(API제공, 보안설정 등)이 있으니, 여유될 때 한번씩 써볼 것을 추천한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>클라우드플레어</category>
      <category>cloudflare</category>
      <category>사이트최적화</category>
      <category>클라우드플레어</category>
      <category>클라우드플레어 Speed</category>
      <author>보오</author>
      <guid isPermaLink="true">https://f-dever-error-log.tistory.com/65</guid>
      <comments>https://f-dever-error-log.tistory.com/65#entry65comment</comments>
      <pubDate>Sun, 10 Apr 2022 16:38:54 +0900</pubDate>
    </item>
    <item>
      <title>[Cloudflare 시리즈2] 클라우드플레어 사이트최적화 - 캐싱</title>
      <link>https://f-dever-error-log.tistory.com/64</link>
      <description>&lt;table style=&quot;border-collapse: collapse; width: 66.9767%; height: 108px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://f-dever-error-log.tistory.com/63&quot;&gt;1. 클라우드플레어 작동원리&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://f-dever-error-log.tistory.com/64&quot;&gt;2. 클라우드플레어 사이트 최적화 - 캐싱&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://f-dever-error-log.tistory.com/65&quot;&gt;3. 클라우드플레어 사이트 최적화 - 스피드&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;클플메뉴.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;1304&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUjHjc/btryRnobdIe/luOucKOXnk3oL7AhPKRQR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUjHjc/btryRnobdIe/luOucKOXnk3oL7AhPKRQR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUjHjc/btryRnobdIe/luOucKOXnk3oL7AhPKRQR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUjHjc%2FbtryRnobdIe%2FluOucKOXnk3oL7AhPKRQR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;741&quot; data-filename=&quot;클플메뉴.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;1304&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드플레어를 이용해 웹페이지 최적화를 하고 싶다면 수많은 메뉴 중 캐싱, 스피드 2가지만 알아도 충분하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 155px; height: 67px;&quot; border=&quot;0&quot; bgcolor=&quot;#DDECFF&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 139px;&quot; data-highlight-colour=&quot;blue&quot;&gt;
&lt;ol style=&quot;list-style-type: none; padding: 0; margin: 0;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1. Caching&lt;/li&gt;
&lt;li&gt;2. Speed&lt;/li&gt;
&lt;/ol&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 페이지에서는 이 중 캐싱을 다룬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;id-[Cloudflare]2.사이트최적화-캐싱-1.Caching상태분석&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. Caching 상태 분석&lt;/b&gt;&lt;/h2&gt;
&lt;h4 id=&quot;id-[Cloudflare]2.사이트최적화-캐싱-①Analytics메뉴활용하기&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;①Analytics 메뉴 활용하기&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;클플 analytics.png&quot; data-origin-width=&quot;2732&quot; data-origin-height=&quot;1154&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blb2nu/btryUgbF9VC/Q8Whazji9iCF9wrfKCHgC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blb2nu/btryUgbF9VC/Q8Whazji9iCF9wrfKCHgC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blb2nu/btryUgbF9VC/Q8Whazji9iCF9wrfKCHgC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fblb2nu%2FbtryUgbF9VC%2FQ8Whazji9iCF9wrfKCHgC1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2732&quot; height=&quot;1154&quot; data-filename=&quot;클플 analytics.png&quot; data-origin-width=&quot;2732&quot; data-origin-height=&quot;1154&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드플레어는 기본적으로 모든 리소스를 캐시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Analytics &amp;gt; Traffic&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;메뉴를 보면 친절하게 캐시된 요청과 캐시되지 않은 요청을 보기 쉽게 차트로 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;id-[Cloudflare]2.사이트최적화-캐싱-②네트워크창에서헤더로분석하기&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;②네트워크창에서 헤더로 분석하기&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;css파일 캐싱중.png&quot; data-origin-width=&quot;1166&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDwnp4/btrySOzYDSc/TKuneGxaGISomTSyNKoq11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDwnp4/btrySOzYDSc/TKuneGxaGISomTSyNKoq11/img.png&quot; data-alt=&quot;네트워크 탭에서 CSS 필터링 한 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDwnp4/btrySOzYDSc/TKuneGxaGISomTSyNKoq11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDwnp4%2FbtrySOzYDSc%2FTKuneGxaGISomTSyNKoq11%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1166&quot; height=&quot;495&quot; data-filename=&quot;css파일 캐싱중.png&quot; data-origin-width=&quot;1166&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;네트워크 탭에서 CSS 필터링 한 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐싱이 잘 되었다면 Size에 memory cache(또는 disk cache)로 나오고 Time이 모두 0이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;캐시파일의 경우 TTFB가 확연히 줄어들어 SEO 향상에도 도움이 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;캐시중일때 네트워크탭.png&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;550&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mwUtB/btryV3iC0Ch/LsixQpZK3qfcPmyzgddf3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mwUtB/btryV3iC0Ch/LsixQpZK3qfcPmyzgddf3k/img.png&quot; data-alt=&quot;클라우트플레어 캐시 파일의 네트워크 탭&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mwUtB/btryV3iC0Ch/LsixQpZK3qfcPmyzgddf3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmwUtB%2FbtryV3iC0Ch%2FLsixQpZK3qfcPmyzgddf3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;693&quot; height=&quot;550&quot; data-filename=&quot;캐시중일때 네트워크탭.png&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;550&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;클라우트플레어 캐시 파일의 네트워크 탭&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐시되고 있는 파일 아무거나 클릭해보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Response Headers의 속성으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;cache-control, cf-cache-status, server&lt;/b&gt;&lt;/span&gt;가 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 캐시컨트롤은 클라우드플레어에서 설정한 값으로 나오는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 화면의 2678400은 초단위로 나타낸 것으로 캐시 TTL 설정으로 1달로 한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;server는 실제 사용중인 웹서버가 아닌 cloudflare로 표시된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cf-cache-status는 캐시 상태를 나타낸 것으로 바로 아래서 더 자세히 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;id-[Cloudflare]2.사이트최적화-캐싱-③cf-cache-status에따른캐시상태분석&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;③&lt;b&gt;cf-cache-status&lt;/b&gt;에 따른 캐시 상태 분석&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;background-color: #ffebe5;&quot;&gt;
&lt;td data-highlight-colour=&quot;red&quot;&gt;&lt;b&gt;HIT&lt;/b&gt;&lt;/td&gt;
&lt;td data-highlight-colour=&quot;red&quot;&gt;정상적으로 캐시되고 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffebe5;&quot;&gt;
&lt;td data-highlight-colour=&quot;red&quot;&gt;&lt;b&gt;MISS&lt;/b&gt;&lt;/td&gt;
&lt;td data-highlight-colour=&quot;red&quot;&gt;클라우드플레어 캐시서버에서 리소스를 못찾아 오리진서버(Origin Server)까지 간 상태&lt;br /&gt;(아무것도 캐시되지 않은 최초 사이트 로드 시 발생함)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;EXPIRED&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;파일이 캐시에 있지만 보관기간이 지나서 오리진서버로 갔다옴&lt;br /&gt;(보통 해당 캐시파일을 지우거나 TTL 시간이 만료되면 발생함)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot;&gt;&lt;b&gt;STALE&lt;/b&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;EXPIRED 되어서 오리진서버로 갔지만 해당 파일을 찾지 못함&lt;br /&gt;(보통 해당 파일이 삭제된 경우 발생함)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background-color: #ffebe5;&quot;&gt;
&lt;td colspan=&quot;1&quot; data-highlight-colour=&quot;red&quot;&gt;&lt;b&gt;BYPASS&lt;/b&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot; data-highlight-colour=&quot;red&quot;&gt;&lt;span&gt;헤더의 Cache-Control 설정이 &quot;no-cache, private, max-age=0&quot;인 경우 오리진서버로 직행함&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;gt;&amp;gt; 캐시컨트롤을 no-cache로 해놓으면 클라우드플레어는 캐싱하지 않음&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot;&gt;&lt;b&gt;UPDATING&lt;/b&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;오리진서버에서 캐시서버로 업데이트 중&lt;br /&gt;(보통 캐시가 만료되어 오리진서버에 갔다가 다시 저장할 때 발생,&lt;br /&gt;주로 요청이 많은 리소스 or 캐시 삭제 후 최초 접속했을 때 일어남)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot;&gt;&lt;b&gt;DYNAMIC&lt;/b&gt;&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;&lt;span&gt;사용자 정의에 따라 캐시하지 않기로 함&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;(클플 공식 문서: &lt;a style=&quot;color: #666666;&quot; href=&quot;https://developers.cloudflare.com/cache/about/default-cache-behavior/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developers.cloudflare.com/cache/about/default-cache-behavior/&lt;/a&gt; )&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;id-[Cloudflare]2.사이트최적화-캐싱-2.클라우드플레어캐시규칙&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 클라우드플레어 캐시 규칙&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드플레어에도 물론 캐시 규칙이 있는데 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; background-color: #ddecff;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td data-highlight-colour=&quot;blue&quot;&gt;&lt;span&gt;① Cache-Control 헤더가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;no-cache, private, max-age=0&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;중 하나로 설정되어 있을 경우 캐시하지 않는다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span style=&quot;background-color: #ddecff;&quot;&gt;② 반대로 Cache-Control 헤더가 **&quot;public&quot;**이면서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;max-age&quot;가 0보다 큰 경우&lt;/b&gt;나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Expires 속성이 미래 날짜로 되어 있는 경우&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;캐시한다.&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;background-color: #ddecff;&quot;&gt;&lt;span style=&quot;background-color: #ddecff;&quot;&gt;③ Cache-Control &quot;max-age&quot;와 Expires가 둘 다 설정된 경우 max-age를 따른다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;id-[Cloudflare]2.사이트최적화-캐싱-확장자기준으로캐시&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;확장자 기준으로 캐시&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음의 확장자를 포함하는 파일들만 캐시한다.&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;bmp&lt;/td&gt;
&lt;td&gt;ejs&lt;/td&gt;
&lt;td&gt;jpeg&lt;/td&gt;
&lt;td&gt;pdf&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;ps&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;ttf&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;class&lt;/td&gt;
&lt;td&gt;eot&lt;/td&gt;
&lt;td&gt;jpg&lt;/td&gt;
&lt;td&gt;pict&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;svg&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;webp&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;css&lt;/td&gt;
&lt;td&gt;eps&lt;/td&gt;
&lt;td&gt;js&lt;/td&gt;
&lt;td&gt;pls&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;svgz&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;woff&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;csv&lt;/td&gt;
&lt;td&gt;gif&lt;/td&gt;
&lt;td&gt;mid&lt;/td&gt;
&lt;td&gt;png&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;swf&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;woff2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;doc&lt;/td&gt;
&lt;td&gt;ico&lt;/td&gt;
&lt;td&gt;midi&lt;/td&gt;
&lt;td&gt;ppt&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;tif&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;xls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot;&gt;docx&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;jar&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;otf&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;pptx&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;tiff&lt;/td&gt;
&lt;td colspan=&quot;1&quot;&gt;xlsx&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 더하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;robots.txt 파일도 캐시&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;id-[Cloudflare]2.사이트최적화-캐싱-3.캐시삭제하기&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;3. 클플 캐시 삭제하기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클플에서는 기본적으로 캐시파일들의 업데이트 상태를 항상 확인하지만 간혹 파일의 변경이 일어났는데 이전 파일을 계속 불러오는 경우가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때는 캐시플러시를 통해 삭제해줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;클플 캐시삭제.png&quot; data-origin-width=&quot;2082&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ekU8Rr/btryU2YAIpF/euky4WA8aWjyLc54WvvTVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ekU8Rr/btryU2YAIpF/euky4WA8aWjyLc54WvvTVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ekU8Rr/btryU2YAIpF/euky4WA8aWjyLc54WvvTVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FekU8Rr%2FbtryU2YAIpF%2Feuky4WA8aWjyLc54WvvTVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2082&quot; height=&quot;506&quot; data-filename=&quot;클플 캐시삭제.png&quot; data-origin-width=&quot;2082&quot; data-origin-height=&quot;506&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐싱 탭에서 할 수 있는데 사용자 지정 제거와 모두 제거 속성이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 웹사이트 캐시 제거시에는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모두 제거를 하면 사이트 전체 리소스의 캐시가 삭제되어 오리진 서버에서 한꺼번에 가져와야 하기 때문에 갑자기 많이 느려질 수 있다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;사용자지정제거.png&quot; data-origin-width=&quot;1634&quot; data-origin-height=&quot;1086&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ukgyv/btryTNNpgKH/bEiTJlGe0bwh8RIJWAKZDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ukgyv/btryTNNpgKH/bEiTJlGe0bwh8RIJWAKZDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ukgyv/btryTNNpgKH/bEiTJlGe0bwh8RIJWAKZDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUkgyv%2FbtryTNNpgKH%2FbEiTJlGe0bwh8RIJWAKZDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;760&quot; height=&quot;505&quot; data-filename=&quot;사용자지정제거.png&quot; data-origin-width=&quot;1634&quot; data-origin-height=&quot;1086&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 사용자 지정 제거를 통해 특정 파일만 제거하는 것이 안전하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐시파일 url로 제거할 수 있는데, 예를 들어 static 경로의 style.css 라는 파일을 삭제하고 싶다면 &quot;${DOMAIN}/static/style.css&quot; 라고 입력하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;id-[Cloudflare]2.사이트최적화-캐싱-4.브라우저캐시TTL설정하기&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 브라우저 캐시 TTL 설정하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TTL(Time To Live)은 캐시파일을 저장되는 시간&lt;/b&gt;을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;브라우저캐시TTL.png&quot; data-origin-width=&quot;2072&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mb2xB/btryV4aNvCv/XZ9KXDQBJRsMnIxsaXo1Ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mb2xB/btryV4aNvCv/XZ9KXDQBJRsMnIxsaXo1Ak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mb2xB/btryV4aNvCv/XZ9KXDQBJRsMnIxsaXo1Ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmb2xB%2FbtryV4aNvCv%2FXZ9KXDQBJRsMnIxsaXo1Ak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2072&quot; height=&quot;478&quot; data-filename=&quot;브라우저캐시TTL.png&quot; data-origin-width=&quot;2072&quot; data-origin-height=&quot;478&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드플레어 캐싱 창에서는 TTL 또한 설정할 수 있는데 최소 30분~1년 단위로 가능하며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'기존헤더유지'를 선택하면 서버에서 설정해놓은 헤더대로 설정이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;클플캐시개발모드.png&quot; data-origin-width=&quot;2082&quot; data-origin-height=&quot;572&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bM1pfr/btryUgiu5Gm/425LlWVkD0oDBV6Yytbf5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bM1pfr/btryUgiu5Gm/425LlWVkD0oDBV6Yytbf5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bM1pfr/btryUgiu5Gm/425LlWVkD0oDBV6Yytbf5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbM1pfr%2FbtryUgiu5Gm%2F425LlWVkD0oDBV6Yytbf5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2082&quot; height=&quot;572&quot; data-filename=&quot;클플캐시개발모드.png&quot; data-origin-width=&quot;2082&quot; data-origin-height=&quot;572&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 개발 모드 ON으로 하면 캐시를 일시적으로 저장하지 않고 오리진 서버에서 바로 가져오게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(직접 끄지 않으면 3시간동안 유지된 후 자동으로 OFF 된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;id-[Cloudflare]2.사이트최적화-캐싱-캐시TTL기준은어떻게설정하면좋을까?&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;캐시 TTL 기준은 어떻게 설정하면 좋을까?&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; background-color: #ddecff;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td data-highlight-colour=&quot;blue&quot;&gt;&lt;span&gt;ⓛ 바뀔 일이 잘 없는 컨텐츠는 보통 3개월 이상 길게 잡는다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;(파비콘 같이 거의 바뀔 일 없는 리소스는 1년 이상 길게 잡기도 한다.)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;② 변동이 많은 리소스의 경우 15분~1시간으로 설정하기도 한다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;b&gt;③ 캐시를 가능한 많이 활용하는 것이 좋다. 아무리 짧은 TTL이라도 no-cache보다 낫다.&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;id-[Cloudflare]2.사이트최적화-캐싱-5.특정리소스만캐시하지않게하려면&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 특정 리소스만 캐시하지 않게 하려면&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 사정에 의해 특정 파일만 캐시에서 제외하고 싶을 때가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럴 때 규칙 메뉴에서 &quot;Page Rule 생성&quot;을 누른 후&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;페이지룰.png&quot; data-origin-width=&quot;1690&quot; data-origin-height=&quot;956&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8gbp2/btryTqMqhcK/sCE9V8bxmCXTnEBGYbywYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8gbp2/btryTqMqhcK/sCE9V8bxmCXTnEBGYbywYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8gbp2/btryTqMqhcK/sCE9V8bxmCXTnEBGYbywYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8gbp2%2FbtryTqMqhcK%2FsCE9V8bxmCXTnEBGYbywYk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1690&quot; height=&quot;956&quot; data-filename=&quot;페이지룰.png&quot; data-origin-width=&quot;1690&quot; data-origin-height=&quot;956&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리소스 경로 입력 후 캐시 수준을 &quot;&lt;b&gt;바이패스&lt;/b&gt;&quot;, 원본 캐시 제어를 ON하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;no캐시규칙.png&quot; data-origin-width=&quot;711&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbmufS/btryTqFH7hu/ZsDEcy3SpytFAO2IKXedQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbmufS/btryTqFH7hu/ZsDEcy3SpytFAO2IKXedQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbmufS/btryTqFH7hu/ZsDEcy3SpytFAO2IKXedQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbmufS%2FbtryTqFH7hu%2FZsDEcy3SpytFAO2IKXedQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;711&quot; height=&quot;600&quot; data-filename=&quot;no캐시규칙.png&quot; data-origin-width=&quot;711&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크 탭에서 cache-control이 &quot;&lt;b&gt;no-cache&lt;/b&gt;&quot;, cf-cache-status가 &quot;&lt;b&gt;DYNAMIC&lt;/b&gt;&quot;으로 설정된 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 규칙 탭에서는 캐시 제어 뿐만 아니라 리디렉션, 무결성검사, HTTPS만 사용하도록 설정 등 보안, DNS에 관한 다양한 룰을 설정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>클라우드플레어</category>
      <category>cf-cache-status</category>
      <category>cloudflare</category>
      <category>사이트최적화</category>
      <category>클라우드플레서 캐싱 적용</category>
      <category>클라우드플레어</category>
      <author>보오</author>
      <guid isPermaLink="true">https://f-dever-error-log.tistory.com/64</guid>
      <comments>https://f-dever-error-log.tistory.com/64#entry64comment</comments>
      <pubDate>Sun, 10 Apr 2022 16:07:12 +0900</pubDate>
    </item>
    <item>
      <title>[Cloudflare 시리즈1] 클라우드플레어 작동원리</title>
      <link>https://f-dever-error-log.tistory.com/63</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Cloudflare-logo.png&quot; data-origin-width=&quot;3649&quot; data-origin-height=&quot;1520&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgWByH/btryV4aGn8J/qmMQTChvhTOukntl2sFKk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgWByH/btryV4aGn8J/qmMQTChvhTOukntl2sFKk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgWByH/btryV4aGn8J/qmMQTChvhTOukntl2sFKk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgWByH%2FbtryV4aGn8J%2FqmMQTChvhTOukntl2sFKk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;460&quot; height=&quot;192&quot; data-filename=&quot;Cloudflare-logo.png&quot; data-origin-width=&quot;3649&quot; data-origin-height=&quot;1520&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 66.9767%; height: 108px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://f-dever-error-log.tistory.com/63&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;1. 클라우드플레어 작동원리&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://f-dever-error-log.tistory.com/64&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2. 클라우드플레어 사이트 최적화 - 캐싱&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://f-dever-error-log.tistory.com/65&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;3. 클라우드플레어 사이트 최적화 - 스피드&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;id-[Cloudflare]1.작동원리-1.클라우드플레어는어떻게작동하는가&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 클라우드플레어는 어떻게 작동하는가&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드플레어(Cloudflare)는 DNS와 CDN 서비스를 제공하는 미국 기업이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인 네임 서비스를 제공하면서 트래픽 필터링도 해주고 Ddos도 차단해주고 분석도 해주고 CDN도 알아서 해주고.. 보안이나 성능, 사이트 안정화 등 여러 면에서 아주 우수한 서비스를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 서비스가 있지만 프론트 엔지니어라면 사이트 성능 개선과 최적화에 초점을 맞추어 클라우드플레어를 이용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 전에 알고 가야할 것이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;0&quot; bgcolor=&quot;#DDECFF&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td data-highlight-colour=&quot;blue&quot;&gt;&lt;span&gt;&lt;b&gt;①클라우드플레어에서는 기본적으로 캐싱을 해준다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;②(만약 프록시서버에서 캐싱 설정을 했으면)&lt;b&gt;클라우드플레어에서 캐싱이 먼저 이루어진다.&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이를 이해하려면 클라우드플레어의 동작 원리를 알아야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Cloudflare 예시.png&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPx72a/btryPCs0yEm/CqnMmuOxyb6h87YDu12Rk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPx72a/btryPCs0yEm/CqnMmuOxyb6h87YDu12Rk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPx72a/btryPCs0yEm/CqnMmuOxyb6h87YDu12Rk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPx72a%2FbtryPCs0yEm%2FCqnMmuOxyb6h87YDu12Rk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1000&quot; height=&quot;500&quot; data-filename=&quot;Cloudflare 예시.png&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(좌) 일반적인 서버&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (우) 클라우드플레어 경유하는 서버&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 웹서버가 nginx 리버스프록시를 사용하고 있다면 이렇다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&amp;lt;일반적인 DNS 서버&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;cf없는 서버.png&quot; data-origin-width=&quot;2181&quot; data-origin-height=&quot;364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdk8zo/btryTqFClHw/RwxFAP5NjFZwTz0n2opd6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdk8zo/btryTqFClHw/RwxFAP5NjFZwTz0n2opd6k/img.png&quot; data-alt=&quot;DNS에서 Nginx 리버스 프록시 경유 후 실제 포트를 띄움&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdk8zo/btryTqFClHw/RwxFAP5NjFZwTz0n2opd6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbdk8zo%2FbtryTqFClHw%2FRwxFAP5NjFZwTz0n2opd6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;100&quot; data-filename=&quot;cf없는 서버.png&quot; data-origin-width=&quot;2181&quot; data-origin-height=&quot;364&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DNS에서 Nginx 리버스 프록시 경유 후 실제 포트를 띄움&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&amp;lt;클라우드플레어 경유하는 DNS 서버&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;cf있는 서버.png&quot; data-origin-width=&quot;2967&quot; data-origin-height=&quot;364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzi0zC/btryZagV7LW/mpEeQKJkx6l9XYopp5upNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzi0zC/btryZagV7LW/mpEeQKJkx6l9XYopp5upNk/img.png&quot; data-alt=&quot;DNS에서 클라우드플레어에 들리고 Nginx 리버스 프록시 경유 후 실제 포트를 띄움&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzi0zC/btryZagV7LW/mpEeQKJkx6l9XYopp5upNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbzi0zC%2FbtryZagV7LW%2FmpEeQKJkx6l9XYopp5upNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2967&quot; height=&quot;364&quot; data-filename=&quot;cf있는 서버.png&quot; data-origin-width=&quot;2967&quot; data-origin-height=&quot;364&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DNS에서 클라우드플레어에 들리고 Nginx 리버스 프록시 경유 후 실제 포트를 띄움&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;유저가 url에 도메인 주소를 치면 &lt;u&gt;클라우드플레어를 경유하여&lt;/u&gt; ip로 된 실제 웹 서버에 도달한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;id-[Cloudflare]1.작동원리-2.캐싱은어디서일어날까?&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 캐싱은 어디서 일어날까?&lt;/b&gt;&lt;/h2&gt;
&lt;p id=&quot;id-[Cloudflare]1.작동원리-①일반적인캐싱&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;①일반적인 캐싱&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;일반적인 캐싱.png&quot; data-origin-width=&quot;2446&quot; data-origin-height=&quot;732&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4R2D3/btrySONv8mh/ymPbK0pS9ZkhKG3jEZ0xkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4R2D3/btrySONv8mh/ymPbK0pS9ZkhKG3jEZ0xkk/img.png&quot; data-alt=&quot;클라우드플레어가 없는 경우&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4R2D3/btrySONv8mh/ymPbK0pS9ZkhKG3jEZ0xkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4R2D3%2FbtrySONv8mh%2FymPbK0pS9ZkhKG3jEZ0xkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;660&quot; height=&quot;198&quot; data-filename=&quot;일반적인 캐싱.png&quot; data-origin-width=&quot;2446&quot; data-origin-height=&quot;732&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;클라우드플레어가 없는 경우&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드플레어 없이 엔진엑스에서 캐싱을 한다면 위 그림처럼 요청서버와 엔진엑스 사이에서 일어날 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20200702_클라우드플레어작동원리_네트워크탭_01.png&quot; data-origin-width=&quot;459&quot; data-origin-height=&quot;273&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dvauMc/btryU2xsJ3m/TWoLmjxjFt2Si29jpcBGj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dvauMc/btryU2xsJ3m/TWoLmjxjFt2Si29jpcBGj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dvauMc/btryU2xsJ3m/TWoLmjxjFt2Si29jpcBGj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdvauMc%2FbtryU2xsJ3m%2FTWoLmjxjFt2Si29jpcBGj0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;459&quot; height=&quot;273&quot; data-filename=&quot;20200702_클라우드플레어작동원리_네트워크탭_01.png&quot; data-origin-width=&quot;459&quot; data-origin-height=&quot;273&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크탭에서 간단하게 확인해볼 수 있는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Response Headers에 &quot;&lt;b&gt;X-Proxy-Cache&lt;/b&gt;&quot; 속성이 프록시 서버 캐싱 여부를 말해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;id-[Cloudflare]1.작동원리-②클라우드플레어캐싱&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;②클라우드플레어 캐싱&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;cf캐싱.png&quot; data-origin-width=&quot;3088&quot; data-origin-height=&quot;780&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cs15Db/btryTr5xxRj/J8DJbXB2biz4GUcg1WRLLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cs15Db/btryTr5xxRj/J8DJbXB2biz4GUcg1WRLLk/img.png&quot; data-alt=&quot;클라우드플레어가 있는 경우&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cs15Db/btryTr5xxRj/J8DJbXB2biz4GUcg1WRLLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcs15Db%2FbtryTr5xxRj%2FJ8DJbXB2biz4GUcg1WRLLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3088&quot; height=&quot;780&quot; data-filename=&quot;cf캐싱.png&quot; data-origin-width=&quot;3088&quot; data-origin-height=&quot;780&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;클라우드플레어가 있는 경우&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드플레어를 사용한다면 오리진 서버로 도달하기 전에 캐싱이 일어난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20200702_클라우드플레어작동원리_네트워크탭_02.png&quot; data-origin-width=&quot;691&quot; data-origin-height=&quot;381&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VWz92/btryTrqZINw/GSU17ZmFwmrYxZFabSfMw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VWz92/btryTrqZINw/GSU17ZmFwmrYxZFabSfMw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VWz92/btryTrqZINw/GSU17ZmFwmrYxZFabSfMw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVWz92%2FbtryTrqZINw%2FGSU17ZmFwmrYxZFabSfMw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;691&quot; height=&quot;381&quot; data-filename=&quot;20200702_클라우드플레어작동원리_네트워크탭_02.png&quot; data-origin-width=&quot;691&quot; data-origin-height=&quot;381&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 네트워크탭에서 보면 &quot;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;cf-cache-status&lt;/b&gt;&lt;/span&gt;&quot; 속성이 추가되었을 것이고 서버는 클라우드플레어로 바뀌어있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;id-[Cloudflare]1.작동원리-③만약엔진엑스캐싱과클라우드플레어캐싱이동시에적용되어있다면?&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;③만약 엔진엑스 캐싱과 클라우드플레어 캐싱이 동시에 적용되어 있다면?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;애초에 엔진엑스까지 갈 일이 없으니 아무리 엔진엑스에서 캐시 설정을 해도 안될 것이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때문에 종종 내가 설정한 Cache-Control이 덮어씌워질 때가 있는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드플레어에서 설정한 값으로 덮어씌워진 경우일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면 엔진엑스에서 max-age를 3달(7776000)로 설정했지만 클라우드플레어 설정에서 1달로 해놓았다면 max-age가 1달(2678400)로 바뀌어있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;id-[Cloudflare]1.작동원리-3.클라우드플레어캐싱특징&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 클라우드플레어 캐싱 특징&lt;/b&gt;&lt;/h2&gt;
&lt;h4 id=&quot;id-[Cloudflare]1.작동원리-①동적,정적파일모두클라우드플레어를거친다.&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;①동적, 정적 파일 모두 클라우드플레어를 거친다.&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정하기 나름이지만 일반적으로는 거의 바뀌지 않는 정적 파일(js, css, img, favicon 등)만 캐시 서버를 거친다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 클라우드플레어는 그런거 없고 동적 파일까지 모두 클라우드플레어를 경유하도록 되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 동적 파일만 분류하여 클라우드플레어를 거치지 않게 하는 것은 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td data-highlight-colour=&quot;grey&quot;&gt;Q. 캐싱이 필요없는 파일까지 클라우드플레어를 거치면 서버가 느려지지 않을까?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;A. 그렇지 않다.클라우드플레어에 따르면 클플에서 전세계에 Edge를 두고 그 엣지들을 이어놓은 네트워크 회선을 사용하고 있기 때문에 거쳐야 할 hops 수가 줄어들어 오히려 빠르다고 한다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;그러나 이 부분은 주의해야할 것이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;한국의 경우 엔터프라이즈 유저(유료 멤버)가 아니면 한국 Egde 사용이 불가하다&lt;/b&gt;고 한다. 상황에 따라 더 느려질 수 있다는 뜻이다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;id-[Cloudflare]1.작동원리-②특정파일만캐싱되게할수있다.&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;②특정 파일만 캐싱되게 할 수 있다.&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드플레어&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Page Rules&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라는 메뉴에서 룰을 추가해줌으로써 일부 파일들은 캐싱이 되지 않게 또는 일부 파일들만 캐싱되게 설정할 수 있고 쿼리문으로도 제어가 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nginx도 설정으로 가능하기 때문에 클플만의 특징은 아니지만 까다로운 정규식을 사용하지 않고 누구나 쉽게 설정할 수 있다는 점.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;id-[Cloudflare]1.작동원리-③클라우드플레어캐싱설정은어디서하는가?&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;③클라우드플레어 캐싱 설정은 어디서 하는가?&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드플레어에는 다양한 기능들이 있는데 이 중 &quot;Caching&quot;에서 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유료 멤버 대상으로는 캐시 분석까지 해주지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;무료여도 캐시 삭제, 캐시할 양 설정, TTL 설정 등 유용한 기능을 제공한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;id-[Cloudflare]1.작동원리-④사이트가다운되어도캐싱페이지를보여주므로일시적으로는문제없다.&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;④사이트가 다운되어도 캐싱페이지를 보여주므로 일시적으로는 문제 없다.&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;클라우드플레어 최대 장점이라고 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>클라우드플레어</category>
      <category>cloudflare</category>
      <category>클라우드플레어</category>
      <category>클라우드플레어 캐싱</category>
      <author>보오</author>
      <guid isPermaLink="true">https://f-dever-error-log.tistory.com/63</guid>
      <comments>https://f-dever-error-log.tistory.com/63#entry63comment</comments>
      <pubDate>Sun, 10 Apr 2022 15:11:21 +0900</pubDate>
    </item>
    <item>
      <title>캐시에 관한 최소한의 모든 것(1)</title>
      <link>https://f-dever-error-log.tistory.com/62</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;** 노션에서 더 편하게 보기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://glistening-seashore-ed4.notion.site/f4a5838d303248918c146b40c9ac4b8a&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://glistening-seashore-ed4.notion.site/f4a5838d303248918c146b40c9ac4b8a&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1645973092059&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;캐시에 관한 최소한의 모든 것&quot; data-og-description=&quot;캐시란?&quot; data-og-host=&quot;glistening-seashore-ed4.notion.site&quot; data-og-source-url=&quot;https://glistening-seashore-ed4.notion.site/f4a5838d303248918c146b40c9ac4b8a&quot; data-og-url=&quot;https://glistening-seashore-ed4.notion.site/f4a5838d303248918c146b40c9ac4b8a&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://glistening-seashore-ed4.notion.site/f4a5838d303248918c146b40c9ac4b8a&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://glistening-seashore-ed4.notion.site/f4a5838d303248918c146b40c9ac4b8a&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;캐시에 관한 최소한의 모든 것&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;캐시란?&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;glistening-seashore-ed4.notion.site&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;캐시란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청에 대한 응답의 복사본을 어딘가에 저장해놓고, 같은 요청이 들어오면 (서버에) 재요청하지 않고 저장한 복사본 데이터를 보내주는 것.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;어떤 요청인가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유저의 GET요청. 보통 POST요청은 캐시하지 않는다. 일반적으로 200, 301, 404 응답을 캐싱한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;어디에 저장하나?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프록시 서버에 생성된 캐시 메모리 또는 클라이언트의 개인적인 공간(브라우저 등)에 저장한다. 이는 추후 설명하게 될 공유캐시(Public)/사설캐시(Private)가 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;왜 이런 행위(캐시)가 필요하나?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본 데이터가 있는 곳은 원본 서버(Origin Server)라고 한다. 웹에서 클라이언트는 브라우저에서 요청을 시작한다. 브라우저를 통한 요청은 서버로 향하는데, 이때 오리진 &lt;b&gt;서버로 가는 행위는 시간과 자원이 오래 걸린다&lt;/b&gt;. 그래서 그 사이에 &lt;b&gt;캐시메모리&lt;/b&gt;라는 공간을 두고, 만약 클라이언트가 동일한 요청을 했고 그 요청에 대한 응답이 동일하다면, 굳이 서버까지 가지 않고 중간에 캐시메모리에서 데이터를 찾아서 던져주기로 한다. 클라이언트는 똑같은 상태의 데이터를 이전보다 더 빨리 받게 된다. 서버는 자원을 아끼고, 클라이언트는 응답을 더 빨리 받고 클라이언트, 서버 둘다 윈윈이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 캐시메모리에는 명확한 제한이 있는데, 바로 &lt;b&gt;크기&lt;/b&gt;다. 일시적으로 복사본을 저장하는 공간인 만큼 서버의 아주 작은 공간만을 할당 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 캐시메모리가 다 차면 안에 있는 데이터를 삭제하여 공간을 만들고, 새로운 요청에 대한 응답을 다시 저장하는데 &lt;b&gt;이때 어떤 데이터를 삭제할 것인지&lt;/b&gt;가 중요해지는데, 이를 결정하는 로직이 &lt;b&gt;캐시 알고리즘&lt;/b&gt;이 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;캐시 알고리즘&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐시 교체 정책이라고도 하며, LRU, LFU, FIFO 등 여러 알고리즘이 있지만 LRU가 가장 많이 쓰인다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;LRU(Least Recently Used)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐시메모리에서 사용된지 가장 오래된 페이지(&amp;mdash; 캐시에서 각 데이터를 일컫는 말)를 지우는 방식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;오랫동안 쓰지 않은 데이터는 앞으로도 안쓸 것이다&amp;rdquo;라는 가정에서 나온 알고리즘이으로, 구현이 쉽고 &lt;b&gt;가장 보편적인&lt;/b&gt; 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  LRU 알고리즘&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;요청이 들어온다.&lt;/li&gt;
&lt;li&gt;캐시에 없는 데이터면 원본 서버에서 데이터를 가져온 후 응답해주면서 캐시에 저장한다.&lt;/li&gt;
&lt;li&gt;캐시에 있는 데이터면 캐시에서 빼서 준다.&lt;/li&gt;
&lt;li&gt;캐시에 없는 데이터를 요청하는데 캐시가 다 찼을 경우, 가장 마지막에 쓰인 데이터를 지우고 방금 요청한 캐시를 가장 뒤(tail)에 둔다.&lt;/li&gt;
&lt;li&gt;캐시에 있는 데이터 요청 시 해당 데이터를 가장 뒤(tail)로 옮기고 응답한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한 것은 가장 최근 응답한 데이터는 항상 맨 뒤로 순서를 옮긴다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열로 생각하면 head에 가까울 수록 오래된 데이터, tail에 가까울 수록 최신 데이터라는 것이다. (array.push &amp;rarr; 최근 페이지)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용 알고리즘은 Doubly Linked List, HashMap이며, 시간복잡도는 O(1)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하고 빠른 알고리즘이지만, 캐시데이터가 언제 사용되었는지를 알기 위해 timestamp을 찍는데, 이 때 오버헤드가 발생할 수 있다는 단점이 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;자바스크립트로 LRU 구현하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아주 유명한 알고리즘인 만큼 코테에도 자주 출제되는데, 자바스크립트로 간단하게 구현할 수 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span&gt;(tail에 있는 데이터가 가장 최신이라고 가정)&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;br /&gt;리퀘스트가 들어온다. 이 때,&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;br /&gt;1. 기존 캐시데이터에 있는지 확인 후&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;br /&gt;2. 캐시에 없으면(MISS)&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; 2-1. 캐시에 넣어준다.&lt;br /&gt;&amp;nbsp; &amp;nbsp; 2-2. 캐시가 가득차있다면, 가장 오래된 데이터를 제거하고 넣어준다. (배열의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;첫번째&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;데이터를 제거)&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;br /&gt;3. 캐시에 있으면(HIT)&lt;br /&gt;&amp;nbsp; &amp;nbsp; 3-2. 해당 데이터를 캐시의 가장 뒤로 보낸다. (배열의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;마지막&lt;/b&gt;으로 보냄)&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; 3-1. 캐시에서 데이터를 꺼낸 뒤 응답한다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;// 캐시에는 사이즈가 있다.
// 사이즈가 5인 캐시메모리(최초에는 비워져 있다고 가정)
const cache_size = 5;
const cache_memory = Array.from({ length: cache_size }, () =&amp;gt; null);

// 클라이언트가 요청하는 데이터
const request = [3, 4, 5, 3, 1, 1, 3, 6, 1, 2, 3, 5, 7, 3, 1];

req.forEach((el) =&amp;gt; {
  const idx = cache.indexOf(el);
  // MISS
  if (idx &amp;lt; 0) {
    if (cache.length &amp;lt; size) {
      cache.push(el);
    } else {
      cache.shift();
      cache.push(el);
    }
  } else {
    // HIT
    cache.splice(idx, 1);
    cache.push(el);
  }
});

console.log(cache);

// [2,5,7,3,1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에서 드는 의문점이 있다. 왜 배열의 가장 첫번째가 아닌 마지막 데이터가 가장 최신 데이터라고 하는걸까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;궁금증을 풀기 위해 head가 가장 신선하다고 여기는 로직(array.unshift)도 테스트해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 로직에서 마지막이 아니라 첫번째로 추가하는 것으로 바꾸면 이렇게 된다.&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;req.forEach((el) =&amp;gt; {
  const idx = cache.indexOf(el);
  // MISS
  if (idx &amp;lt; 0) {
    if (cache.length &amp;lt; size) {
      cache.unshift(el);
    } else {
      cache.pop();
      cache.unshift(el);
    }
  } else {
    // HIT
    cache.splice(idx, 1);
    cache.unshift(el);
  }
});
console.log(cache);

// [1,3,7,5,2]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;console.time, console.timeEnd로 시간을 계산한 결과&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tail에 최신데이터를 넣은 함수는 0.084ms, head에 최신 데이터를 넣은 함수는 0.117ms가 걸렸는데, 아마 속도때문에 tail에 최신 데이터를 넣기로 한 것 같다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;HTTP 요청의 캐시 설정들: Cache-Control&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MDN(&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Cache-Control&quot;&gt;https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Cache-Control&lt;/a&gt;)에 가면 이미 자세히 나와있지만, 공부할 겸 한번 더 정리해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;** (!) 라고 표시한 것은 비표준임(&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Cache-Control#browser_compatibility&quot;&gt;호환성 확인하기&lt;/a&gt;)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;max-age&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐시의 수명. 지정한 시간(초) 동안 유효하다. ** 리소스가 유효하다고 판단하는 최대 시간으로, 이 안에 리소스가 바뀌었다면 update된다. Expires와 차이: 거의 없는데 둘 다 있으면 max-age가 이긴다. (max-age &amp;gt; expires)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) max-age=3153600 // 1년동안 캐싱&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;s-max-age&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공유 캐시(프록시 캐시)에만 적용되는 max-age. 사설캐시는 적용되지 않는다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;max-stale&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 캐시데이터에 max-age, 유효기간이 지난 캐시가 있을 때 이 캐시를 사용할지 여부. 있으면 지정된 시간동안 이 캐시를 사용한다는 얘기 ex) max-stale=3600 // 캐시가 만료되고 나서도 1시간 동안은 이 캐시를 사용&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;stale-while-revalidate&lt;/span&gt;(!)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;max-stale과 비슷하지만 비동기 요청 동안 사용된다. 요청하는 동안 유효기간이 지난 캐시를 얼마만큼(얼마나 오랫동안) 받아들일지 여부로, 요청에 최대한 빠르고 유연하게 대응하기 위한 것이다. SWR, ReactQuery에서 이 설정이 사용된다. ex) max-age=600, stale-while-revalidate=30 // 600초가 지나서 캐시가 만료된 상태이지만, 새로운 데이터를 원본서버에서 찾고 응답이 올 때까지 그 사이 30초 동안은 일단 만료된 캐시를 보냄.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;must-revalidate&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐시 만료 후 다시 조회할 경우 반드시 오리진 서버에 요청한다는 것으로, 만료된 캐시를 절대로 재사용하지 않는 다는 것이다. (그 데이터가 원본서버 데이터와 동일하건 말건 간에)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;proxy-revalidate&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;must-revalidate와 동일하지만 공유 캐시(프록시 캐시)에만 적용된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;immutable&lt;/span&gt;(!)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(만료되지 않는 한) 응답 데이터가 계속 변하지 않을 것이니, 원본을 확인하지 않고 &amp;ldquo;계~속 캐시해라&amp;rdquo; 오리진 서버에 데이터가 바뀌었는지 확인하지 않는 것으로 주로 변하지 않는 폰트, 이미지 등에 쓰인다. 이 속성의 강점은 사용자가 페이지를 새로고침 할 때마다 매번 원본과 대조하지 않아도 되니, 불필요한 요청을 하지 않을 수 있다는 것이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;public&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 공유캐시(프록시 캐시)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공유서버에 저장해도 되는지 여부를 나타냄&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;private&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 사설캐시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공용 응답이 아닌 유저 개개인의 민감한 정보를 저장해야 할 경우 사용하는 속성으로, 공유 서버(프록시)에 저장하지 않고 개인 공간(브라우저 등)에 저장한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;only-if-cached&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신본이 있을 때 서버에 확인하지 않음&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;no-cache&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐시를 쓰기 전에 오리진 서버에 &amp;ldquo;이거 써도 되냐&amp;rdquo;고 컨펌 받음(재검증) &amp;rarr; 캐시를 안한다는 뜻이 아님&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;no-store&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐시를 끄는 설정 &amp;rarr; 이게 캐시 안한다는 뜻&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;캐시 끄는 설정: &lt;span style=&quot;color: #ee2323;&quot;&gt;no-cache, no-store, must-revalidate&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;캐시 키는 설정: &lt;span style=&quot;color: #ee2323;&quot;&gt;public, max-age=31536000 // 1년&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;보너스&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;What is &lt;span style=&quot;color: #006dd7;&quot;&gt;E-tag&lt;/span&gt;?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 캐시를 구분짓기 위해 붙이는 숫자, 문자가 섞인 string값으로 원본 데이터가 변하면 E-tag도 변한다. 따라서 E-tag가 변하면 원본 서버에 다시 요청한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;** E-tag의 단점은 서버 간에 값을 공유할 수 없다는 것이다. 즉, 서버마다 고유한 E-tag 값을 가지고 있어서 똑같은 데이터여도 서버가 여러개면 E-tag가 달라진다. 그러면 원본은 그대로인데 매번 상태가 바뀌었다고 판단하여 캐시가 무용지물이 된다. 이를 방지하기 위해 E-tag을 끄는 방법도 있다. E-tag을 꺼도 Last-Modified라는 타임스탬프로 최신 데이터인지를 판단할 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;nbsp;HIT&lt;/span&gt; || &lt;span style=&quot;color: #ee2323;&quot;&gt;MISS &lt;/span&gt;?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크 탭을 보면 이렇게 cache-status가 &lt;b&gt;HIT&lt;/b&gt; 또는 &lt;b&gt;MISS&lt;/b&gt; 등으로 나오는데, 캐시를 했는지, 안했는지 여부다. (cf-cache-status은 클라우드플레어 캐시임)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;HIT&lt;/b&gt;: 캐시메모리에 있어서 캐시데이터를 가져온 상태&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MISS&lt;/b&gt;: 캐시메모리에서 찾지 못해서 원본 서버에서 가져온 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HIT, MISS는 깊게 파보면 Hit latency(rate), Miss latency(rate) 등 과연 얼마나 잘 캐시하고 있는지 성능을 측정하는 척도로 쓰이는 개념이 있는데, 이번 글에서는 이정도로만 마치고 다음에 이어서 파보겠다.&lt;/p&gt;</description>
      <category>Javascript</category>
      <category>E-Tag</category>
      <category>Hit</category>
      <category>LRU</category>
      <category>Miss</category>
      <category>stale-while-revalidate</category>
      <category>웹서버 캐시</category>
      <category>캐시</category>
      <category>캐시 설정</category>
      <category>캐시 알고리즘</category>
      <author>보오</author>
      <guid isPermaLink="true">https://f-dever-error-log.tistory.com/62</guid>
      <comments>https://f-dever-error-log.tistory.com/62#entry62comment</comments>
      <pubDate>Sun, 27 Feb 2022 23:45:20 +0900</pubDate>
    </item>
    <item>
      <title>[코딩테스트 기초] 회문문자열 판별(재귀함수, array splice을 이용하여 - javascript)</title>
      <link>https://f-dever-error-log.tistory.com/61</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;회문문자열(&lt;span style=&quot;color: #000000; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;palindrome)은 거꾸로 읽어도 알파벳이 똑같은 글자를 말한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;알고리즘의 가장 기초적인 문제로 자주 등장하는데, 자바스크립트에서는 reverse 메소드를 이용하여 많이 푼다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;여기에서는 재귀함수와 splice 메소드를 이용하여 풀어보겠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;먼저 args로 넘어온 문자를 split을 이용해 Array로 만들어주고, 재귀함수(recursive)로 돌린다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;재귀함수를 사용할 때는 무조건 if/else 구문으로 조건을 만들 것.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;특정 조건을 통과하면 true을 리턴, 아니면 false을 리턴하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기서 특정 조건은 두 개가 되는데,&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하나는 배열의 길이가 1 이하일 때.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;글자가 1글자면 무조건 회문문자열이 된다. ex) 'a', 'i', 'x', ...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;나머지 하나는?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot;&lt;b&gt;첫번째 글자와 마지막 글자가 같을 때&lt;/b&gt;&quot;이다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 조건을 통과하면 재귀함수를 또 호출하는데, 이번에는 Array을 splice하여 배열의 첫번째 원소와 마지막 원소를 제해야 한다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이렇게 해서 더이상 나눌 수 없을 때(array.length&amp;lt;=1)까지 반복하여 끝까지 살아남으면 true, 아니면 false을 리턴하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위 시나리오를 코드로 구현하면 이러하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1645337342568&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 회문 판별(리스트 슬라이스 이용)
function palindrome(letter) {
  const arr = letter.split(&quot;&quot;);
  function DFS(list) {
    if (list[0] === list(list.length - 1)) {
      DFS(list.splice(0, list.length - 1));
      return true;
    } else return false;
  }
  return DFS(arr);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이렇게 쉽게 회문문자열을 자바스크립트로 구현해보았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(p.s. 대/소문자 구분을 안한다면 최초에 toLowerCase() 또는 toUpperCase()을 사용하여 문자열의 대소문자를 통일해주면 된다.)&lt;/span&gt;&lt;/p&gt;</description>
      <category>코딩테스트</category>
      <category>palindrome</category>
      <category>자바스크립트</category>
      <category>재귀함수</category>
      <category>코딩테스트</category>
      <category>회문문자열</category>
      <author>보오</author>
      <guid isPermaLink="true">https://f-dever-error-log.tistory.com/61</guid>
      <comments>https://f-dever-error-log.tistory.com/61#entry61comment</comments>
      <pubDate>Sun, 20 Feb 2022 15:11:23 +0900</pubDate>
    </item>
    <item>
      <title>[코딩테스트 기본] 10진수를 2진수로 바꾸기 (Javascript)</title>
      <link>https://f-dever-error-log.tistory.com/60</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;사실 자바스크립트에서는 Object.prototype.toString() 이라는 Web API로 진수 변환을 바로 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;toString의 인자로 radix(기수)을 넣으면 바로 변환을 해준다. (2~36까지만)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 3을 2진수로 바꾸고 싶으면 아래와 같이 하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1645326387545&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let n = 3;
let res = n.toString(2);
console.log(res);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 결과는 '11'이 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 개발자라면 웹 API를 이용하지 않고 그냥 만들 수 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드로 구현하기 전에 수학(!!)으로 10진수를 2진수로 바꿔보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10진수로 된 정수 a를 2진수로 바꾼다고 하면 a를 2로 나눈 나머지와 몫을 다시 2로 나눈 나머지, 몫을 다시 2로 나눈 나머지,, 이렇게 몫을 더이상 2로 나눌 수 없을 때까지 2로 나누고 나머지를 기억해놨다가 이어붙이면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글로 하면 머리아프니까 흔히 하던 식으로 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;10진수를2진수로.png&quot; data-origin-width=&quot;2621&quot; data-origin-height=&quot;1477&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7goiQ/btrtJAZ4Cj8/BI1txyhYrxjK5WEwOXRtG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7goiQ/btrtJAZ4Cj8/BI1txyhYrxjK5WEwOXRtG0/img.png&quot; data-alt=&quot;10진수를 2진수로 바꾸는 식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7goiQ/btrtJAZ4Cj8/BI1txyhYrxjK5WEwOXRtG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7goiQ%2FbtrtJAZ4Cj8%2FBI1txyhYrxjK5WEwOXRtG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;740&quot; height=&quot;417&quot; data-filename=&quot;10진수를2진수로.png&quot; data-origin-width=&quot;2621&quot; data-origin-height=&quot;1477&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;10진수를 2진수로 바꾸는 식&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 나눗셈 하듯이 나누되, 아래로 식이 이어지면서 옆에 나머지를 쓴다. 나머지는 1 또는 0. 더이상 나눌 수 없을 때(몫이 1이 될 때)까지 나누고 최종적으로 남은 몫과 나머지를 이어붙인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 과정을 코드로 구현하면 여러가지 방법이 있을 수 있겠지만, 재귀함수를 사용해서 쉽게 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;재귀함수&lt;/b&gt;는 어떤 함수를 자기 자신을 호출하는 함수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재귀함수 호출 시 if/else 구문을 사용하여 원하는 답에 다다를 때 까지 if문으로 조건을 걸어주고, 그렇지 않으면 끊임없이 자기 자신을 호출한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시나리오를 작성해보면, 우선 함수가 특정 숫자(2진수로 바꾸어야 할 값)를 인자로 받고, 해당 숫자를 계속 2로 나눈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언제까지 나누냐, 더이상 나눌 수 없을 때 까지인데, 몫이 1이거나 혹은 인자가 0이 될 때 까지이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1로 하면 조건을 1보다 작거나 같게 걸어야 하지만, 더 깔끔하고 알아보기 쉽게 짜려면 인자가 0이 될 때 까지로 하는게 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0이 되면 재귀함수를 그만두면 되니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건에 걸리지 않으면(나눌 수 있으면) 2로 나눈 나머지를 인자로 넣는다. 2로 나눈 나머지를 코드로 구현하면 주어진 String을 파싱하여 정수를 리턴하는 parseInt을 쓰면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 나머지를 특정 변수에 담아 기억해놨다가, 최종 리턴값이 될 전역변수에 +=로 이어붙이면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, 변수에 할당하는 순서가 중요한데, 재귀함수로 먼저 나누고 난 뒤의 몫을 할당해야 한다. 재귀함수로 나누기 전에 할당해버리면 숫자의 순서가 바뀌게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종적으로 구현한 코드는 아래과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1645327215520&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution(n) {
  let answer = &quot;&quot;;
  function DFS(L) {
    // inner 함수(내부 함수)
    if (L === 0) return;
    else {
      DFS(parseInt(L / 2, 10));
      const k = L % 2;
      answer += String(k);
    }
  }
  DFS(n);
  return answer;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트로 위에 직접 구했던 3, 5, 18을 대입해보면 11, 101, 10010으로 잘 나오는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>코딩테스트</category>
      <category>2진법</category>
      <category>2진수 구하기</category>
      <category>js 2진법</category>
      <category>알고리즘</category>
      <category>자바스크립트</category>
      <category>코딩테스트</category>
      <author>보오</author>
      <guid isPermaLink="true">https://f-dever-error-log.tistory.com/60</guid>
      <comments>https://f-dever-error-log.tistory.com/60#entry60comment</comments>
      <pubDate>Sun, 20 Feb 2022 12:22:11 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js 에러로그] Error: Package subpath './lib/parser' is not defined by &amp;quot;exports&amp;quot;</title>
      <link>https://f-dever-error-log.tistory.com/59</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;nodejs + nextjs로 앱을 실행하던 중 갑자기 로컬에서 아래와 같이 패키지 에러가 났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20220208_package_error.png&quot; data-origin-width=&quot;2202&quot; data-origin-height=&quot;782&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZIPN6/btrsO2wXVXS/rH5z9ueHMnB7wSb6kRhqn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZIPN6/btrsO2wXVXS/rH5z9ueHMnB7wSb6kRhqn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZIPN6/btrsO2wXVXS/rH5z9ueHMnB7wSb6kRhqn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZIPN6%2FbtrsO2wXVXS%2FrH5z9ueHMnB7wSb6kRhqn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2202&quot; height=&quot;782&quot; data-filename=&quot;20220208_package_error.png&quot; data-origin-width=&quot;2202&quot; data-origin-height=&quot;782&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그는 Error: Package subpath './lib/parser' is not defined by &quot;exports&quot;.. (이하 생략)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭘 잘못 건드렸나.. npm 모듈을 다 지우고 다시 깔아봐도 같은 에러다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글링을 해보니 node 버전이 16 버전 이상인 경우 위 에러가 발생할 수 있다고 한다. (원인은 모른다..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nvm current로 현재 버전을 확인해보니 버전이 갑자기 16으로 올라가있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;14 버전으로 급히 다운그레이드 후 재실행하니 아주 잘~된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘의 교훈: &lt;b&gt;알수없는 에러가 뜨면 node js 버전 호환성을 확인해보자!&lt;/b&gt;&lt;/p&gt;</description>
      <category>NextJs</category>
      <category>NextJS</category>
      <category>nodejs</category>
      <category>nvm</category>
      <category>package error</category>
      <author>보오</author>
      <guid isPermaLink="true">https://f-dever-error-log.tistory.com/59</guid>
      <comments>https://f-dever-error-log.tistory.com/59#entry59comment</comments>
      <pubDate>Tue, 8 Feb 2022 22:50:48 +0900</pubDate>
    </item>
    <item>
      <title>[코딩테스트] 2022 KAKAO BLIND RECRUITMENT 신고 결과 받기 (Javascript)</title>
      <link>https://f-dever-error-log.tistory.com/58</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;문제 보러 가기: &lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/92334&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://programmers.co.kr/learn/courses/30/lessons/92334&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1644127776583&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 연습 - 신고 결과 받기&quot; data-og-description=&quot;문제 설명 신입사원 무지는 게시판 불량 이용자를 신고하고 처리 결과를 메일로 발송하는 시스템을 개발하려 합니다. 무지가 개발하려는 시스템은 다음과 같습니다. 각 유저는 한 번에 한 명의 &quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/92334&quot; data-og-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/92334&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/wfnSx/hyNloqNgIO/WGIbsB8ZJjCuMkM7rKEVy1/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/VcaqL/hyNlcRqCqN/aEsz5oMKdUPetMRSp9xZxK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/92334&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/92334&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/wfnSx/hyNloqNgIO/WGIbsB8ZJjCuMkM7rKEVy1/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/VcaqL/hyNlcRqCqN/aEsz5oMKdUPetMRSp9xZxK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 연습 - 신고 결과 받기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;문제 설명 신입사원 무지는 게시판 불량 이용자를 신고하고 처리 결과를 메일로 발송하는 시스템을 개발하려 합니다. 무지가 개발하려는 시스템은 다음과 같습니다. 각 유저는 한 번에 한 명의&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;나의 풀이&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1644127860372&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution(id_list, report, k) {
    var answer = Array.from({length: id_list.length}, ()=&amp;gt;0);
    var report_map = new Map(); // 신고 명단
    id_list.forEach((id)=&amp;gt;{
        report_map.set(id, []); // 신고 명단 초기화(각 id마다 빈 배열을 할당)
    })
    var report_count = new Map(); // 피신고자 누적 횟수
    var report_set = new Set(report);

    report_set.forEach((re)=&amp;gt;{
        var [reporter, reported] = re.split(&quot; &quot;);
        // 신고 명단 작성
        report_map.set(reporter, [...report_map.get(reporter), reported]);
        // 피신고자 누적 횟수 계산
        if(report_count.has(reported)) report_count.set(reported, report_count.get(reported) + 1);
        else report_count.set(reported, 1);
    })

    const reported_list = Array.from(report_map.values());

    report_count.forEach((value, key)=&amp;gt;{
        if(value &amp;gt;= k) {
            reported_list.forEach((list, index)=&amp;gt;{
                if(list.includes(key)) answer[index] = answer[index] + 1;
            })
        }
    })

    return answer;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;해설&amp;gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 풀기 위해서는 누가 누구를 신고했는지에 대한 &quot;&lt;span style=&quot;color: #006dd7;&quot;&gt;신고 명단&lt;/span&gt;&quot;과, 누가 몇번 신고 당했는지에 대한 &quot;&lt;span style=&quot;color: #ef6f53;&quot;&gt;피신고 누적 횟수&lt;/span&gt;&quot;가 필요하다.&lt;br /&gt;전자는 각 유저의 신고 명단에&amp;nbsp;&lt;span style=&quot;color: #006dd7;&quot;&gt;최종 신고 처리된 사람들이 있다면 카운트해주기 위함&lt;/span&gt;이고, 후자는 각 유저별로&amp;nbsp;&lt;span style=&quot;color: #ef6f53;&quot;&gt;신고 당한 횟수가 k번을 넘었는지&lt;/span&gt;&amp;nbsp;알기 위함이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;lt;사용 알고리즘&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Javascript&amp;nbsp;&lt;b&gt;Map, Set&lt;/b&gt;&amp;nbsp;자료형&lt;br /&gt;Map, Set의 개념만 알고 있다면 두 개를 활용해서 충분히 풀 수 있는 문제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. answer는 id_list의 갯수만큼 각 원소가 0으로 초기화된 배열로 만들어준다. (Array.from 이용)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 구하고자 하는 값이 각 유저 별 최종 신고 완료 메일을 받은 횟수를 구하는 것이기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. id_list의 순서대로 report_map을 빈 배열로 초기화 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 이렇게 한 이유는 추후에 map의 value만을 가지고 최종 신고 처리된 사람들이 있다면 그 누적 값을 answer 배열에서 같은 index을 찾아서 바로 넣어주기 위함이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 피신고 누적 횟수를 구하기 위해 report_count을 Map 객체로 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. report 배열로 신고 명단을 만드는데, 그 전에 ** 중복 신고 무효처리를 위해 Set을 이용, report 원본 배열에서 중복 제거를 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; ex) &quot;muzi prodo&quot;, &quot;muzi prodo&quot; 는 무지가 프로도를 2번이나 신고한 것이기 때문에 1번으로 친다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 중복 제거된 report_set 배열을 forEach loop로 돌려서 신고명단을 작성함과 동시에, 피신고 횟수를 누적한다. (불필요한 for문의 반복을 피하기 위함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 신고 명단(report_map)의 value만을 가져다가 id_list로 정렬된 신고 명단(reported_list) 배열을 구한다. (map.prototype.values 이용)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. 누적 횟수 배열을 forEach loop을 돌려 k번 이상 신고된 유저가 있다면, reported_list에 해당 유저가 들어있는지 구한 후(array.prototype.includes 이용) 있다면 answer의 index번째 값에 1을 더한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;총평&amp;gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 중복 제거하는 것을 깜빡하여 테스트 문제 2번을 틀렸었다. 중복 제거 로직만 잘 끼워넣으면 풀기에는 무난하다. Map, Set의 개념을 확실히 아는 것이 중요하다. 6~7번 과정은 좀 더 직관적이고 단순하게 할 수 있을 것 같은데 더 생각해봐야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;p.s. 괜찮은 방법이 있다면 댓글로 공유 부탁드립니다~&lt;/p&gt;</description>
      <category>코딩테스트</category>
      <category>javascript</category>
      <category>자바스크립트</category>
      <category>카카오</category>
      <category>카카오 블라인드</category>
      <category>카카오코테</category>
      <category>코딩테스트</category>
      <author>보오</author>
      <guid isPermaLink="true">https://f-dever-error-log.tistory.com/58</guid>
      <comments>https://f-dever-error-log.tistory.com/58#entry58comment</comments>
      <pubDate>Sun, 6 Feb 2022 15:11:15 +0900</pubDate>
    </item>
  </channel>
</rss>