HTTP 캐싱에서 304 Not Modified 응답 이해하기

웹 애플리케이션을 개발할 때, 효율적인 리소스 처리는 성능에 매우 중요합니다. 특히 파일 접근 및 브라우저 캐싱에 관련하여 그렇습니다. 이 프로세스를 최적화하는 한 가지 방법은 304 Not Modified HTTP 응답을 올바르게 활용하는 것입니다. 이 응답은 브라우저에 요청한 리소스가 마지막으로 검색한 이후 변경되지 않았음을 알려 주어, 브라우저가 다시 다운로드하지 않고 캐시된 버전을 계속 사용할 수 있도록 합니다. 하지만 언제 이 응답을 보내야 하는지 어떻게 알 수 있을까요? 단계별로 살펴봅시다.

확인해야 할 주요 HTTP 헤더

304 Not Modified 응답을 보낼지 여부를 결정하기 위해서는 클라이언트의 브라우저가 전송한 특정 HTTP 헤더를 확인해야 합니다. 주목해야 할 두 가지 주요 헤더는 다음과 같습니다:

  1. Etag: 이 헤더는 특정 버전의 리소스를 위한 고유 식별자 역할을 합니다. 브라우저는 자신의 캐시된 Etag와 서버의 Etag를 비교하여 일치 여부를 확인합니다.
  2. If-None-Match: 이 헤더는 브라우저에 의해 전송되며 캐시된 Etag 값을 포함합니다. 리소스가 변경되지 않았다면 서버는 304로 응답할 수 있습니다.

무엇을 확인해야 할까요

  • 브라우저의 Etag가 존재하는 경우: 브라우저가 요청에 Etag 또는 If-None-Match 헤더를 포함한다면, 이는 이전에 캐시된 리소스 버전이 있다는 것을 나타냅니다.
  • 따옴표 처리: 브라우저는 때때로 Etag 값을 따옴표로 감쌉니다. 비교하기 전에 이러한 따옴표를 제거해야 합니다.

초기 응답을 위한 필수 헤더

리소스를 처음 전송할 때(일반적으로 200 OK 응답과 함께) 리소스 상태에 대해 브라우저에 정보를 제공하는 관련 헤더를 포함하는 것이 필수적입니다:

  • Last-Modified: 리소스가 마지막으로 변경된 시간을 나타냅니다. 이는 Etag와 함께 캐시 유효성 검사를 위한 대체 확인 방법이 될 수 있습니다.
  • Etag(이전에 언급한 바와 같이): 이는 리소스에 대해 생성되어야 하며, 미래의 캐시 유효성 검사를 용이하게 하기 위해 응답 헤더에 포함되어야 합니다.

로직 구현하기

다음은 304 Not Modified 응답을 보내기 위한 로직을 구현하는 방법을 보여주는 간략한 의사 코드 예제입니다:

server_etag = gen_etag_for_this_file(myfile)
etag_from_browser = get_header("Etag")

if etag_from_browser does not exist:
    etag_from_browser = get_header("If-None-Match")
if the browser has quoted the etag:
    strip the quotes (e.g. "foo" --> foo)

set server_etag into http header

if etag_from_browser matches server_etag
    send 304 return code to browser

예제 서버 로직 스니펫

서버 로직에서 이를 구현하는 방법은 다음과 같습니다:

/* 클라이언트는 Etag 또는 If-None-Match 중 하나를 설정해야 합니다 */
mketag(etag, &sb);

etagin = apr_table_get(r->headers_in, "Etag");
if (etagin == NULL)
    etagin = apr_table_get(r->headers_in, "If-None-Match");
if (etag != NULL && etag[0] == '"') {
    /* 존재하는 경우 따옴표 제거 */
    int sl; 
    sl = strlen(etag);
    memmove(etag, etag+1, sl+1);
    etag[sl-2] = 0;
}   

apr_table_add(r->headers_out, "ETag", etag);

if (etagin != NULL && strcmp(etagin, etag) == 0) {
    /* Etag가 일치하는 경우 304 상태 반환 */
    rc = HTTP_NOT_MODIFIED;
}

최종 생각

304 Not Modified 응답을 어떻게 그리고 언제 보내야 하는지 아는 것은 서버 부하를 효과적으로 줄이고 사용자 경험을 향상시키는 데 도움이 됩니다. 클라이언트가 이후 정확한 캐시 유효성 검사 요청을 할 수 있도록 초기 응답에서 EtagLast-Modified 헤더를 포함하는 것의 중요성을 잊지 마세요. Etag 생성에 대한 질문이나 추가 구현 지원이 필요한 경우, 더 자세한 예제에 대해 언제든지 문의해 주세요. 해피 코딩!