์›น

E-Tag

์ธํ„ฐ๋„ท์„ ํ†ตํ•œ ๋ฆฌ์†Œ์Šค ๋ฒ„์ „ ๊ด€๋ฆฌ ๋ฐฉ๋ฒ•

  • #http
  • #header
  • #caching

ETag (์—”ํ„ฐํ‹ฐ ํƒœ๊ทธ)๋Š” ๋ฆฌ์†Œ์Šค ๋ฒ„์ „์„ ์‹๋ณ„ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” HTTP ์‘๋‹ต ํ—ˆ๋”์ž…๋‹ˆ๋‹ค. ์ด๋Š” HTTP/1.1 ์‚ฌ์–‘์˜ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค.

ETag์™€ ํ•จ๊ป˜ ์›๊ฒฉ ์„œ๋ฒ„๋กœ ์š”์ฒญ์ด ์ „์†ก๋˜๋ฉด ์„œ๋ฒ„๋Š” ETag๊ฐ’์„ ๋น„๊ตํ•˜์—ฌ ํŠน์ • ๋ฆฌ์†Œ์Šค ๋ณ€๊ฒฝ ๋˜์—ˆ๋Š”์ง€ ๋˜๋Š” ๋™์ผํ•˜๊ฒŒ ์œ ์ง€๋˜๋Š”์ง€๋ฅผ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ๊ฐ’์ด ๊ฐ™์œผ๋ฉด ์„œ๋ฒ„๋Š” ์š”์ฒญ๋œ ์ฝ˜ํ…์ธ  ์—†์ด ์ƒํƒœ ์ฝ”๋“œ 304๋กœ ์‘๋‹ตํ•  ๊ฒ๋‹ˆ๋‹ค.

๋ถ€์ธ ์„ฑ๋ช…

ํ•œ๊ตญ์–ด ์‹ค๋ ฅ์ด ๋ถ€์ ํ•˜์—ฌ ์ด ๊ธ€์ด ๊ตฌ๊ธ€ ๋ฒˆ์—ญ๊ธฐ๋ฅผ ์ฃผ๋กœ ํ™œ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ถ€์ •ํ™•ํ•œ ๋ฌธ๋ฒ•๊ณผ ์–ดํœ˜๊ฐ€ ์žˆ์„์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์  ์–‘ํ•ด ๋ถ€ํƒ๋“œ๋ฆฌ๋ฉฐ, ์ถ”ํ›„์— ๋‹ค์‹œ ๊ฒ€ํ† ํ•˜์—ฌ ์ˆ˜์ •ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋™์ž‘์€ ํšจ์œจ์ ์ธ ์บ์‹ฑ๊ณผ ์กฐ๊ฑด๋ถ€ ์š”์ฒญ์„ ์šฉ์ดํ•˜๊ฒŒ ํ•˜์—ฌ ๋Œ€์—ญํญ ์‚ฌ์šฉ๋Ÿ‰์„ ์ค‘์ด๊ณ  ์›น ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ๋˜ํ•œ, ETag๋Š” ๋Œ€์ƒ ๋ฆฌ์†Œ์Šค๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ ค๋Š” ์—ฌ๋Ÿฌ ์š”์ฒญ์ด ๋™์‹œ์— ๋ฐœ์ƒํ•  ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์Ÿ ์กฐ๊ฑด์„ ๋ฐฉ์ง€ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ˜„์ƒ์„ "๊ณต์ค‘ ์ถฉ๋Œ"์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์ž‘๋™์›๋ฆฌ

  1. ์ƒ์„ฑ: ์„œ๋ฒ„๋Š” ๋จผ์ € ์‚ฌ์šฉ์ž ๊ฐ์ฒด์™€ ๊ฐ™์€ ํŠน์ • ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ๊ณ ์œ  ์‹๋ณ„์ž๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ฝ˜ํ…์ธ ์˜ ํ•ด์‹œ ๋˜๋Š” ์ง€๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ฐ์ฒด๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜๋ฉด ๊ณ ์œ  ์‹๋ณ„์ž๋„ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.
  2. ๊ฒ€์ฆ: ๋™์ผํ•œ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ํ›„์† ์š”์ฒญ์˜ ๊ฒฝ์šฐ ํด๋ผ์ด์–ธํŠธ๋Š” If-None-Match ํ—ค๋”๋ฅผ ํ†ตํ•ด ETag ๊ฐ’์„ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.
  3. ๋น„๊ต: ์„œ๋ฒ„๋Š” ํด๋ผ์ด์–ธํŠธ ETag ๊ฐ’์„ ์„œ๋ฒ„๊ฐ€ ๊ณ„์‚ฐํ•œ ํ˜„์žฌ ETag ๊ฐ’๊ณผ ๋น„๊ตํ•˜์—ฌ ๋™์ผํ•œ์ง€ ํŒ๋‹จํ•˜๊ณ  ๋น„๊ต ๊ฒฐ๊ณผ์— ๋”ฐ๋ผ 304 Not Modified ๋˜๋Š” 200 OK๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

Node.js์— ๊ตฌํ˜„

๋‹ค์Œ ์ฝ”๋“œ๋Š” Express.js์—์„œ ETag(๊ฐ•๋ ฅ)๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

index.js
app.get('/api/user/:id', (req, res) => {
    const user = getUser(req.params.id);
    const etag = '"' + hash(user) + '"';

    if (req.headers['if-none-match'] === etag) {
        return res.status(304).end();
    }

    res.set('ETag', etag);
    res.json(user);
});

๊ฐ•๋ ฅํ•œ E-Tag ์•ฝํ•œ E-Tag

ETag์—๋Š” ๋‘ ๊ฐ€์ง€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๊ฐ•๋ ฅํ•œ ETags: ๋™์ผํ•œ ๋ฆฌ์†Œ์Šค๋ฅผ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ETag๋Š” ๋ฆฌ์†Œ์Šค ์ž์ฒด ์ „์ฒด์—์„œ ํŒŒ์ƒ๋œ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.
ETag: "abc123"
  • ์•ฝํ•œ ETags: ์˜๋ฏธ์  ๋™๋“ฑ์„ฑ์„ ๋‚˜ํƒ€๋‚ด์ง€๋งŒ ๋ฐ”์ดํŠธ ๋‹จ์œ„์˜ ๋™์ผ์„ฑ์€ ๋‚˜ํƒ€๋‚ด์ง€ ์•Š์œผ๋ฉฐ W/ ์ ‘๋‘์‚ฌ๊ฐ€ ๋ถ™์Šต๋‹ˆ๋‹ค.
ETag: W/"abc123"
ํฐ๋”ฐ์˜ดํ‘œ๋กœ ๋ฌถ์ธ ETag

์˜ฌ๋ฐ”๋ฅธ ETag๊ฐ€ ํฐ๋”ฐ์˜ดํ‘œ๋กœ ๋ฌถ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์˜ user ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

{
  "name": "Shaun",
  "age": 27
}

๋‹ค์Œ ํ‘œ๋Š” ๊ฐ•๋ ฅํ•œ ETag์™€ ์•ฝํ•œ ETag๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

์œ ํ˜•ETag๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์†์„ฑETag์„ค๋ช…
๊ฐ•๋ ฅํ•œ๋ชจ๋“  ์†์„ฑ"Abc123"์ •ํ™•ํ•œ ์ผ์น˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค
์•ฝํ•œname ์†์„ฑ๋งŒW/"Abc124"๋ถ€๋ถ„ ์ผ์น˜๋Š” ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค

E-Tag์˜ ๋‹จ์ 

๋กœ๋“œ ๋ฐธ๋Ÿฐ์„œ ์ถฉ๋Œ

๋กœ๋“œ ๋ฐธ๋Ÿฐ์„œ ๋’ค์— ์žˆ๋Š” ์—ฌ๋Ÿฌ ์„œ๋ฒ„์—์„œ ETag ์ƒ์„ฑ ์ถฉ๋Œ์„ ๋ณด์—ฌ์ฃผ๋Š” ๋‹ค์ด์–ด๊ทธ๋žจ

ETag๋ฅผ ์—ฌ๋Ÿฌ ์„œ๋ฒ„ ์ธ์Šคํ„ด์Šค์˜ ์—ญ๋ฐฉํ–ฅ ํ”„๋ก์‹œ ์—ญํ• ์„ ํ•˜๋Š” ๋กœ๋“œ ๋ฐธ๋Ÿฐ์„œ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ๋ฆฌ์†Œ์Šค๊ฐ€ ์ˆ˜์ •๋˜์ง€ ์•Š์•˜๋”๋ผ๋„ ๊ฐœ๋ณ„ ์„œ๋ฒ„์—์„œ ์ „์†ก๋˜๋Š” ETag๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ETag๋Š” ์‚ฌ์‹ค์ƒ ์“ธ๋ชจ๊ฐ€ ์—†์œผ๋ฉฐ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„์— ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ์›น ์„œ๋ฒ„๋ฅผ ๊ตฌ์„ฑํ•˜์—ฌ ๊ฒฐ์ •์  ETag๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ณต์žกํ•œ ๊ตฌํ˜„

ETag๋ฅผ ์ธ์‹ํ•˜๋Š” ํ™˜๊ฒฝ์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ๋Š” If-None-Match ํ—ค๋”์™€ ํ•จ๊ป˜ ์š”์ฒญ์„ ์ „์†กํ•˜๋Š” ๋กœ์ง์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•˜๋ฉฐ, ์„œ๋ฒ„๋Š” ํ•ด๋‹น ํ—ค๋”๋ฅผ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„์˜ ETag ํ๋ฆ„์„ ๋ณด์—ฌ์ฃผ๋Š” ๋‹ค์ด์–ด๊ทธ๋žจ

๋น„์œค๋ฆฌ์ ์ธ ์ถ”์ 

Hulu๋ฐ ๋‹ค๋ฅธ ๋Œ€๊ธฐ์—…๊ฐ€ ETag๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž๋“ค์„ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์‰ฝ๊ฒŒ ์ ‘๊ทผํ•˜๊ณ  ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋Š” ์ฟ ํ‚ค์™€ ๋‹ฌ๋ฆฌ, ETag๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ์™„์ „ํžˆ ๊ด€๋ฆฌ๋ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์š”์ฒญ์„ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— ETag ํ—ค๋”๋ฅผ ์ˆ˜๋™์œผ๋กœ ์‚ญ์ œํ•  ๋งŒํผ ๊ธฐ์ˆ ์— ๋Šฅ์ˆ™ํ•˜์ง€ ์•Š๋‹ค๋ฉด, ์ด๋ฅผ ์šฐํšŒํ•  ๋ฐฉ๋ฒ•์ด ์‚ฌ์‹ค์ƒ ์—†์Šต๋‹ˆ๋‹ค.

ETag๊ฐ€ ์ถ”์ ์„ ์–ด๋–ป๊ฒŒ ๋‚จ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋ณด์—ฌ์ฃผ๋Š” ๋‹ค์ด์–ด๊ทธ๋žจ

์ด ํšŒ์‚ฌ๋Š” ETag๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž์—๊ฒŒ 1ํ”ฝ์…€ ์ด๋ฏธ์ง€์™€ ๊ฐ™์€ ์š”์ฒญ๋˜์ง€ ์•Š์€ ๋ฆฌ์†Œ์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์š”์ฒญ์„ ์ˆ˜์‹ ํ•  ๋•Œ๋งˆ๋‹ค ํ•ญ์ƒ 304 ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋™์ž‘์€ ์‚ฌ์šฉ์ž๊ฐ€ ์‹œ์ฒญํ•œ ์˜ํ™”์™€ ๊ฐ™์ด ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‚ฌ์šฉ์ž์˜ ํ™œ๋™์„ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๋Š” ์„œ๋ฒ„์™€์˜ ์„ธ์…˜์„ ๊ธฐ๋ณธ์ ์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ 

Mozilla. ETag. Retrieved 2025, April 20 from https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/ETag
Wikipedia. HTTP ETag. Retrieved 2025, April 20 from https://en.wikipedia.org/wiki/HTTP_ETag
Nasser, H. HTTP Caching with E-Tags - (Explained by Example).https://www.youtube.com/watch?v=TgZnpp5wJWU
Privacy suit filed over use of ETags .ย Lexology. https://www.lexology.com/library/detail.aspx?g=cfd44331-0c27-4c37-aeb0-d31b7f7c729e