사전 Last-Modified
표준

Last-Modified

gabury1고친 사람 github-actions[bot]

Last-Modified 는 서버가 보내는 내용을 마지막으로 고친 때를 함께 알려 줍니다. 받는 쪽은 다음 요청에 그 시각을 적어 그 뒤로 바뀌었는지를 묻습니다. 서버는 바뀐 것이 없다는 답을 본문 없이 짧게 돌려줍니다. 같은 내용을 두 번 내려보내는 일이 그만큼 줄어듭니다.

쉽고 빠른 이해

Last-Modified 는 서버가 이 내용을 마지막으로 고친 때를 알려 주는 값입니다. 브라우저가 어제 받아 둔 로고 이미지를 오늘도 그냥 써도 되는지 따질 때 이 시각을 근거로 씁니다.

이 값이 없으면 브라우저와 캐시는 안 바뀐 파일도 매번 처음부터 다시 받습니다. 바뀌었는지 물어볼 근거가 없기 때문입니다.

어떻게 도는가:

  1. 서버가 내용을 보내면서 마지막으로 고친 시각을 한 줄 덧붙입니다
  2. 받는 쪽은 내용과 그 시각을 함께 저장합니다
  3. 다음 요청에 그 시각을 적어 보내면 서버는 그 뒤로 바뀐 것이 있는지만 답합니다

대가는 정밀도입니다. 1초 안에 두 번 고치면 두 판이 같은 값을 답니다. 서버 시계에 기대는 값이라 시계가 어긋나면 판단도 어긋납니다.

상세

Last-Modified 는 HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 프로토콜) 응답에 실리는 헤더 필드입니다. 서버는 지금 내려보내는 내용을 마지막으로 고쳤다고 믿는 시각을 여기 적습니다. 그 시각은 요청을 다 처리한 시점을 기준으로 정합니다.

한 페이지는 대개 여러 조각이 합쳐진 결과입니다. 글과 이미지와 설정이 각각 따로 바뀝니다. 그래서 이 값은 보통 그 조각들 중 가장 최근에 바뀐 때가 됩니다. 어느 조각을 어떻게 세는지는 서버를 만드는 쪽에 맡겨져 있습니다.

값의 생김새

값은 시각 하나입니다. 적는 꼴도 정해져 있습니다.

Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT

요일, 일·월·연, 시·분·초, 그리고 GMT(Greenwich Mean Time, 그리니치 표준시)가 차례로 붙습니다. 시간대는 언제나 GMT 로 적습니다. 그래서 보내는 쪽도 받는 쪽도 환산할 일이 없습니다.

초까지만 적습니다. 그보다 잘게는 나누지 않습니다.

지금은 안 쓰는 옛 꼴이 둘 더 있습니다. 오래된 서버가 아직 그 꼴로 보내서 받는 쪽은 그 둘도 읽을 줄 알아야 합니다. 같은 시각을 세 꼴로 적으면 이렇습니다.

Tue, 15 Nov 1994 12:45:26 GMT
Tuesday, 15-Nov-94 12:45:26 GMT
Tue Nov 15 12:45:26 1994

둘째는 요일 이름을 다 적고 연도를 두 자리로 줄인 꼴입니다. 셋째는 예전 C 라이브러리가 시각을 찍어 내던 꼴이라 시간대 표시가 없습니다. 보내는 쪽은 첫째 꼴 하나로만 보냅니다.

안 바뀌었는지 물어보는 쓰임

이 값의 주된 쓰임은 조건부 요청입니다. 조건부 요청은 「이 조건이 맞을 때만 해 주세요」라는 단서를 붙여 보내는 요청입니다. 브라우저는 앞서 받아 둔 시각을 그 단서로 씁니다.

sequenceDiagram
    participant 브라우저
    participant 서버
    브라우저->>서버: 로고 이미지를 주세요
    서버-->>브라우저: 본문 + 마지막으로 고친 시각
    Note over 브라우저: 본문과 시각을 함께 저장한다
    브라우저->>서버: 그 시각 뒤로 바뀌었나요
    서버-->>브라우저: 안 바뀌었습니다 · 본문 없음

둘째 요청에 붙는 단서가 If-Modified-Since 헤더입니다. 값으로는 앞서 받아 둔 시각을 그대로 적습니다. 서버는 그 시각 이후로 바뀐 것이 없으면 본문을 만들지 않고 304 Not Modified 라는 상태 코드만 돌려줍니다. 오가는 양이 헤더 몇 줄로 줄어듭니다.

바뀌었으면 서버는 새 본문과 새 시각을 함께 보냅니다. 받는 쪽은 저장해 둔 사본을 새것으로 갈아 끼웁니다.

쓰기 요청도 이 시각을 단서로 답니다. If-Unmodified-Since 는 「내가 본 뒤로 아무도 안 고쳤을 때만 고쳐라」는 뜻입니다. 남이 먼저 고쳐 둔 내용을 모르고 덮어쓰는 일을 막습니다.

시각이라서 생기는 한계

내용이 어느 버전인지 가리키는 짧은 값을 검증자라고 부릅니다. Last-Modified 는 그 검증자 중 시각 쪽입니다.

시각을 초까지만 적으므로 같은 초 안에 두 번 고쳐진 내용은 두 버전이 같은 값을 답니다. 뒤엣것을 놓칠 수 있다는 뜻입니다. 그래서 이 값은 약한 검증자로 다룹니다.

같은 버전인지를 바이트 하나까지 따져야 하는 쓰임에는 이 값만으로 모자랍니다. 내려받다 끊긴 파일의 뒷부분만 이어받는 경우가 그렇습니다. 그럴 때는 버전마다 붙는 짧은 문자열인 ETag 를 함께 씁니다.

같은 일을 하는 두 값이 어디서 갈리는지 나란히 놓으면 이렇습니다.

Last-Modified ETag
값의 근거 마지막으로 고친 시각 버전마다 서버가 만드는 문자열
구분 단위 초 내용이 바뀌면 곧바로 갈린다
서버가 드는 짐 파일의 수정 시각을 읽으면 된다 버전마다 값을 만들어 들고 있어야 한다

그래서 값싼 Last-Modified 를 기본으로 두고, 버전을 정확히 갈라야 할 때만 ETag 를 얹습니다.

시계도 이 값의 발목을 잡습니다. Date 는 서버가 응답에 적는 현재 시각입니다. 서버는 그보다 미래인 Last-Modified 를 만들지 않습니다. 미래 시각이 들어가면 받는 쪽의 판단이 어그러지기 때문입니다.

서버 시계 자체가 어긋나면 이 값도 같이 어긋납니다. 시계가 뒤로 밀린 동안 고친 내용에는 예전 시각이 붙습니다. 받는 쪽은 자기가 들고 있는 시각보다 앞선 값을 보고 안 바뀌었다고 믿어, 낡은 사본을 계속 내줍니다.

캐시가 만료를 짐작하는 근거

서버가 「언제까지 써도 된다」고 못박아 주는 시각, 곧 만료 시각을 응답에 안 넣을 때가 있습니다. 캐시는 그럴 때 만료 시각을 스스로 짐작해도 됩니다.

저장해 둔 사본을 언제까지 그냥 내줘도 되는지를 신선도라고 부릅니다. 짐작한 값도 그 판단에 씁니다.

Last-Modified 가 있으면 그 시각 이후로 흐른 시간의 일부를 신선한 기간으로 잡습니다. 흔히 쓰는 비율은 10퍼센트 정도입니다. 반년째 안 바뀐 문서라면 앞으로 보름 남짓은 그냥 내줘도 된다고 보는 어림입니다.

관련 항목

이 시각과 함께 응답에 실리는 필드

ETag · Date · Expires · Cache-Control · Age

이 시각을 조건으로 적어 보내는 요청 헤더

If-Modified-Since · If-Unmodified-Since · If-None-Match · If-Range

조건을 따진 결과로 돌아오는 상태 코드

304 Not Modified · 412 Precondition Failed · 상태 코드

이 값의 성질을 가르는 검증자 분류

검증자 · 약한 검증자 · 강한 검증자 · 엔티티 태그 · 불투명 검증자

이 값을 읽어 판단하는 캐시 개념

조건부 요청 · 재검증 · 신선도 · 캐시 키 · HTTP 캐시 · 브라우저 캐시 · CDN

이 필드를 정의하는 표준 문서

RFC 9110 · RFC 9111 · RFC 7232 · RFC 7234

이것이 속하는 상위 분류

HTTP · 헤더 · 필드 · 표현 메타데이터 · 캐싱 · 타임스탬프

다른 이름: Last-Modified 헤더 · Last-Modified 필드 · 마지막 수정 시각