- ETag 헤더는 캐시 관련 헤더
- 서버에서 제공되는 컨텐츠의 식별번호 → 웹서버에서 제공하는 컨텐츠도 각각의 고유 식별정보을 가짐
- ETag HTTP 응답 헤더는 특정 버전의 리소스를 식별하는 식별자
- 웹 서버가 내용을 확인하고 변하지 않았으면, 웹 서버로 full 요청을 보내지 않기 때문에, 캐쉬가 더 효율적이게 되고, 대역폭도 아낄 수 있음
- 내용이 변경되었다면, "mid-air collisions"이라는 리소스 간의 동시 다발적 수정 및 덮어쓰기 현상을 막는데 유용하게 사용
- 특정 URL 의 리소스가 변경된다면, 새로운 ETag 가 생성
- ETag 헤더는 지문(finger printer)과 같은 역할을 하면서 다른 서버들이 추적하는 용도에 이용
- ETag 헤더를 비교하여 리소스가 서로 같은지의 여부를 빠르게 판단할 수 있지만, 서버에서 무기한으로 지속될 수 있도록 설정할 수도 있음
- 캐시버서와 웹브라우저는 ETag 헤더를 이용해서 캐싱된 컨텐츠들이 유효한지 갱신이 필요한지를 결정
ETag의 두 가지종류 → Strong ETag와 Weak ETag
1. Strong ETag
- Strong ETag는 바이트 단위로 컨텐츠가 동일함을 의미
- Strong ETag를 가지고 있는 캐싱된 컨텐츠는 Range 요청에 대해서 응답이 가능
- Strong ETag 예시
Strong ETag : "abcdefg"
2. Weak ETag
- Weak ETag는 바이트단위로 동일 X
- 일반적으로 캐시된 컨텐츠로는 사용 가능
- 바이트 단위까지 같지는 않기 때문에 Range 요청에 대한 응답이 불가능
- Weak ETag 예시
Weak ETag : w/"abcdefg"
실제 헤더의 ETag 값 예시
- ETag 값은 보통 "리소스의 해시값 - 마지막 수정 시간의 해시값" 으로 구성
- 아래 예시를 보면 대시(-)를 기준으로 "48ff5"는 리소스의 해시값, "55559540ad680"은 마지막 수정 시간의 해시값
- 캐시서버는 일반적으로 자신의 캐싱된 컨텐츠를 비교할때 ETag 값을, If-Match, If-None-Match와 함께 사용
문법
1. W/ Optional
- 'W/'는 weak validator가 사용 의미 → 대/소문자를 구분
- Weak validators는 만들기는 쉽지만 비교하기에는 효율성이 떨어짐
- 'W/'를 사용하지 않는 Strong validators는 비교하기에는 이상적이지만 효율적으로 만들기 어려움
- 동일한 자원의 두 가지 Weak validator Etag 값은 동일할 수 있지만, 바이트 단위까지 동일하지 않음
2. etag_value
- etag_value는 요청된 값을 ASCII 코드와 같이 고유한 형태로 나타냄 → 예 : "675af34563dc-tr34"
- ETag의 값을 생성하는 방법(Method)은 단순히 한가지로 정해져있지 않음
- 콘텐츠의 해시, 마지막으로 수정된 타임스탬프의 해시, 혹은 그냥 개정번호를 이용
3. ETag 사용 형식
ETag: W/"<etag_value>"
ETag: "<etag_value>"
4. ETag 사용 예시
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
ETag: W/"0815"
공중 충돌 방지(Avoiding mid-air collisions)
- ETag 헤더는 If-Match 헤더와 함께 사용함으로 공중 편집 충돌(mid-air edit collisions)을 감지 가능
- 예를 들어 MDN을 편집할 때 현재 위키 콘텐츠가 해시되어 응답의 Etag를 넣음
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4
- Wiki 페이지(데이터 게시)에 변경 사항을 저장하는 POST 요청에는 신선도(freshness)를 확인할 ETag 값이 있는 If-Match 헤더가 포함.
If-Math: "33a64df551425fcc55e4d42a148795d9f25f89d4"
- 해시가 일치하지 않으면 문서가 중간에 편집되었음을 의미하며 412 응답코드(Precondition Failed) 오류가 발생
변경되지 않은 리소스 캐싱(Caching of unchanged resources)
- ETag 헤더의 또 다른 사용 사례는 변경되지 않은 리소스(Caching of unchanged resources)를 캐시하는 것
- 사용자가 주어진 URL(기존 ETag 보유)을 다시 방문할 때, 클라이언트는 If-None-Match 헤더 필드를 활용하여 기존의 컨텐츠가 변경되었는지 확인
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
- 서버는 클라이언트의 ETag(If-None-Match와 함께 전송됨)를 현재 버전의 리소스에 대한 ETag와 비교하고 두 값이 일치하면(즉, 리소스가 변경되지 않은 경우) 서버는 304 Not Modified 상태를 다시 보냄
- 응답의 캐시된 버전이 여전히 사용할 수 있음을 클라이언트에 알림(freshness)
클라이언트와 서버 간 통신 과정 설명
1. 첫 요청에 대한 응답
- 클라이언트가 서버에게 요청을 보냄
$ curl -H "Accept: application/json" -i http://localhost:8080/spring-boot-rest/foos/1
- 서버는 ETag 헤더를 응답 Header에 담아 클라이언트에게 응답
HTTP/1.1 200 OK ETag: "f88dd058fe004909615a64f01be66a7" Content-Type: application/json;charset=UTF-8 Content-Length: 52
2. 재요청에 대한 응답
클라이언트는 재요청할 때 ETag를 Header의 If-None-Match 헤더에 담아 서버에 요청을 보냄.
$ curl -H "Accept: application/json" \ -H 'If-None-Match: "f88dd058fe004909615a64f01be66a7"' \ -i http://localhost:8080/spring-boot-rest/foos/1
리소스가 바뀌지 않았기 때문에 서버는 304 Not Modified를 클라이언트에게 응답 (ETag는 이전 요청에 대한 응답과 같음)
HTTP/1.1 304 Not Modified ETag: "f88dd058fe004909615a64f01be66a7"
PUT 메소드를 사용하여 서버의 컨텐츠를 변경
$ curl -H "Content-Type: application/json" -i -X PUT --data '{ "id":1, "name":"Transformers2"}' http://localhost:8080/spring-boot-rest/foos/1
서버의 컨텐츠가 정상적으로 변경되었다는 내용을 서버가 응답
HTTP/1.1 200 OK ETag: "d41d8cd98f00b204e9800998ecf8427e" Content-Length: 0
클라이언트가 이전 재요청 내용을 다시 서버에게 보냄 → 요청을 다시 할 때는 마지막으로 가지고 있던 ETag를 담아서 보냄
$ curl -H "Accept: application/json" -H 'If-None-Match: "f88dd058fe004909615a64f01be66a7"' -i http://localhost:8080/spring-boot-rest/foos/1
클라이언트에서 보낸 ETag와 서버의 ETag가 다르기 때문에 요청을 처리 → 리소스가 바뀌었으니 새로운 ETag를 Header에 담아 보내고, 새로운 요청을 처리했기 때문에 서버는 200 OK를 응답
HTTP/1.1 200 OK ETag: "03cb37ca667706c68c0aad4cb04c3a211" Content-Type: application/json;charset=UTF-8 Content-Length: 56
3. 304 Not Modified 응답 코드
- 캐시를 목적으로 사용하는 status code
- 클라이언트에게 응답이 수정되지 않았음을 알려줌
- 클라이언트는 서버에게 304 응답 코드를 받으면, 클라이언트는 계속해서 응답의 캐시된 버전을 사용 가능
'HTTP > HTTP 헤더' 카테고리의 다른 글
HTTP 프로토콜 Expires 헤더 (0) | 2022.06.25 |
---|---|
HTTP 프로토콜 Expect 헤더 (0) | 2022.06.25 |
HTTP 프로토콜 Date 헤더 (0) | 2022.06.25 |
HTTP 프로토콜 Content-Type 헤더 (0) | 2022.06.25 |
HTTP 프로토콜 Content-Encoding 헤더 (0) | 2022.06.25 |