HTTP 캐싱 101: 필수 정보
Takashi Yamamoto
Infrastructure Engineer · Leapcell

HTTP 캐싱이란
HTTP 캐싱은 서버 부하를 줄이고, 클라이언트 응답 시간을 단축하며, 네트워크 대역폭을 절약하여 웹 성능을 향상시키는 기술입니다. HTTP 캐싱에는 강제 캐싱과 협상 캐싱 두 가지 유형이 있습니다.
강제 캐싱
강제 캐싱을 사용하면 클라이언트는 서버에 요청을 보내지 않고 지정된 기간 내에 로컬 캐시된 리소스를 직접 사용할 수 있습니다. 강제 캐싱은 서버에서 지정한 응답 헤더, 주로 Cache-Control 및 Expires 필드를 통해 제어됩니다.
Cache-Control
Cache-Control은 최대 유효 기간(max-age
), 캐시 공유 가능 여부(public
또는 private
), 수정 허용 여부(no-cache
또는 no-store
)를 지정하는 범용 헤더입니다.
예:
Cache-Control: max-age=3600
위의 내용은 리소스가 3600초 동안 유효하며 캐시될 수 있음을 나타냅니다.
Expires
Expires는 캐시의 절대 만료 시간을 지정하는 더 이상 사용되지 않는 필드입니다.
예:
Expires: Wed, 23 Aug 2024 03:36:26 GMT
이는 리소스가 2024년 8월 23일 오전 3시 36분 26초에 만료됨을 의미합니다. Cache-Control과 Expires가 모두 있는 경우 Cache-Control이 우선합니다.
협상 캐싱
협상 캐싱은 클라이언트가 모든 요청에 대해 리소스가 업데이트되었는지 서버에 확인해야 합니다. 업데이트되지 않은 경우 서버는 304
상태 코드와 빈 응답 본문으로 응답하여 클라이언트가 로컬 캐시를 계속 사용하도록 합니다. 업데이트된 경우 서버는 200
상태 코드와 새 리소스를 반환하여 로컬 캐시를 대체합니다. 협상 캐싱에는 서버와 클라이언트 모두의 헤더가 포함되며, 주로 Last-Modified/If-Modified-Since 및 ETag/If-None-Match입니다.
Last-Modified/If-Modified-Since
Last-Modified는 리소스의 마지막 수정 시간을 나타내는 서버 측 필드입니다. 예:
Last-Modified: Tue, 22 Aug 2024 02:36:26 GMT
이는 리소스가 2024년 8월 22일 오전 2시 36분 26초에 마지막으로 수정되었음을 의미합니다.
If-Modified-Since는 리소스의 마지막 검색 시간을 나타내는 클라이언트 측 필드입니다. 예:
If-Modified-Since: Tue, 22 Aug 2024 02:36:26 GMT
이는 클라이언트가 2024년 8월 22일 오전 2시 36분 26초에 리소스를 검색했음을 의미합니다. 두 타임스탬프가 같거나 Last-Modified가 더 이전인 경우 리소스가 업데이트되지 않았습니다. Last-Modified가 더 늦은 경우 리소스가 업데이트되었습니다.
ETag/If-None-Match
ETag는 리소스의 고유 식별자를 나타내는 서버 측 필드입니다. 예:
ETag: '5d3a9f6d-1f86'
이는 리소스의 식별자가 "5d3a9f6d-1f86"
임을 나타냅니다.
If-None-Match는 리소스의 예상 식별자를 나타내는 클라이언트 측 필드입니다. 예:
If-None-Match: '5d3a9f6d-1f86'
이는 클라이언트가 리소스 식별자가 "5d3a9f6d-1f86"
일 것으로 예상함을 나타냅니다.
두 값이 일치하면 리소스가 업데이트되지 않았습니다. 값이 다르면 리소스가 업데이트되었습니다.
HTTP 캐싱 모범 사례
협상 캐싱과 강제 캐싱을 결합하면 불필요한 네트워크 요청을 효과적으로 줄이면서 사용자가 항상 최신 콘텐츠를 사용할 수 있도록 할 수 있습니다.
일반적인 접근 방식:
강제 캐싱: 정적 리소스(예: CSS, JS, 이미지)의 경우 캐시 기간을 길게 설정합니다. 이렇게 하면 브라우저가 서버에 연결하지 않고 로컬 스토리지에서 직접 리소스를 검색할 수 있습니다.
협상 캐싱: 변경될 수 있는 리소스의 경우 협상 캐싱을 사용합니다. 브라우저는 리소스가 변경되었는지 확인하기 위해 요청을 보냅니다. 그렇지 않으면 서버는 304 Not Modified
응답으로 응답하여 브라우저가 로컬 캐시를 사용하도록 합니다. 리소스가 변경된 경우 서버는 200 OK
및 업데이트된 리소스로 응답합니다.
예시 구현:
Express.js를 백엔드 프레임워크로 사용한다고 가정해 보겠습니다.
const express = require('express'); const app = express(); // 강제 캐싱: 정적 리소스에 대한 캐시 설정 app.use( '/static', express.static('public', { maxAge: '1y', // 캐시 기간은 1년 }) ); // 협상 캐싱: ETag 및 Last-Modified 사용 app.get('/resource', (req, res) => { const content = '...'; // 리소스 콘텐츠 가져오기 const etag = generateETag(content); // ETag 생성 // If-None-Match 헤더 확인 if (req.headers['if-none-match'] === etag) { res.status(304).end(); // 리소스가 변경되지 않았으므로 304 반환 } else { res.setHeader('ETag', etag); res.send(content); // 리소스가 변경되었으므로 새 콘텐츠 반환 } }); function generateETag(content) { return require('crypto').createHash('md5').update(content).digest('hex'); } app.listen(3000, () => { console.log('Server is running on port 3000'); });
주요 고려 사항
-
버전 관리: 강제 캐싱 효과를 극대화하려면
/static/js/main.2024082301.js
와 같이 리소스 URL에 버전 정보를 포함합니다. 리소스가 업데이트되면 버전 번호를 변경하여 사용자가 항상 최신 버전을 얻도록 합니다. -
협상 캐싱 비용: 협상 캐싱은 불필요한 데이터 전송을 줄이지만 여전히 네트워크 왕복이 필요합니다. 거의 변경되지 않는 리소스의 경우 강제 캐싱이 더 효율적일 수 있습니다.
Leapcell은 백엔드 프로젝트 호스팅을 위한 최고의 선택입니다
Leapcell은 웹 호스팅, 비동기 작업 및 Redis를 위한 차세대 서버리스 플랫폼입니다.
다국어 지원
- Node.js, Python, Go 또는 Rust로 개발하세요.
무제한 프로젝트를 무료로 배포
- 사용량에 대해서만 비용을 지불합니다. 요청도 없고, 요금도 없습니다.
탁월한 비용 효율성
- 유휴 요금 없이 사용한 만큼만 지불합니다.
- 예: $25로 평균 응답 시간 60ms에서 694만 건의 요청을 지원합니다.
간소화된 개발자 경험
- 간편한 설정을 위한 직관적인 UI.
- 완전 자동화된 CI/CD 파이프라인 및 GitOps 통합.
- 실행 가능한 통찰력을 위한 실시간 메트릭 및 로깅.
간편한 확장성 및 고성능
- 쉬운 동시성 처리를 위한 자동 확장.
- 운영 오버헤드가 제로입니다. 빌드에만 집중하세요.
설명서에서 자세히 알아보세요!
X에서 팔로우하세요: @LeapcellHQ