ETag: khái niệm, cơ chế bộ nhớ đệm và cấu hình tiêu đề

Tác giả: IT Sectr Đã đăng: 2026-03-09 Thời gian đọc: 8 phút

ETag (Entity Tag) là một tiêu đề HTTP gán một định danh duy nhất cho một phiên bản tài nguyên trên máy chủ, cho phép máy khách kiểm tra hiệu quả tính phù hợp của dữ liệu được lưu trong bộ nhớ đệm. Khi yêu cầu lặp lại, trình duyệt hoặc ứng dụng gửi ETag đã lưu và máy chủ so sánh nó với hiện tại: nếu khớp, nó trả về trạng thái 304 Not Modified mà không có nội dung phản hồi. Theo RFC 7232 (IETF, 2014), các yêu cầu có điều kiện với ETag giảm khối lượng dữ liệu truyền tải lên tới 95% cho các tài nguyên được yêu cầu thường xuyên. Điều này làm cho tiêu đề này trở nên quan trọng đối với hiệu suất của ứng dụng di động.

Điểm chính

  • ETag — một tiêu đề HTTP với định danh phiên bản tài nguyên duy nhất cho các yêu cầu có điều kiện và bộ nhớ đệm
  • Cách hoạt động — máy chủ tạo một hash nội dung hoặc số phiên bản, máy khách gửi nó trong tiêu đề If-None-Match
  • ETag mạnh và yếu — mạnh (nội dung giống hệt byte) và yếu (nội dung tương đương về mặt ngữ nghĩa, tiền tố W/)
  • 304 Not Modified — phản hồi của máy chủ khi ETag khớp, tiết kiệm băng thông và tăng tốc tải
  • ETag vs Last-Modified — ETag chính xác hơn (hash nội dung), Last-Modified đơn giản hơn (ngày), kết hợp cho hiệu quả tối đa

ETag là gì?

ETag (Entity Tag) là một tiêu đề phản hồi HTTP chứa định danh duy nhất cho một phiên bản cụ thể của một tài nguyên. Máy chủ tính toán ETag dựa trên nội dung tệp, siêu dữ liệu hoặc số lần sửa đổi và gửi nó đến máy khách trong phản hồi cho một yêu cầu GET. Máy khách lưu định danh này và trong các yêu cầu tiếp theo đến cùng tài nguyên, gửi nó trong tiêu đề If-None-Match. Nếu tài nguyên không thay đổi, máy chủ phản hồi với 304 Not Modified và máy khách sử dụng bản sao đã lưu trong bộ nhớ đệm.

Định dạng ETag được xác định trong RFC 7232 dưới dạng chuỗi được đặt trong dấu ngoặc kép: "33a64df551425fcc55e4d42a148795d9f25f89d4". Giá trị có thể là hash SHA-1 của nội dung tệp, số phiên bản tăng dần, sự kết hợp inode-số-thời gian cho các tệp tĩnh hoặc một token ngẫu nhiên do máy chủ tạo. Yêu cầu duy nhất là giá trị phải thay đổi khi tài nguyên thay đổi và không được thay đổi nếu tài nguyên giữ nguyên.

ETag thuộc về cơ chế yêu cầu có điều kiện (conditional requests) — một trong những tối ưu cơ bản của giao thức HTTP. Không giống như các yêu cầu vô điều kiện, nơi máy chủ luôn trả về phản hồi đầy đủ, một yêu cầu có điều kiện cho phép máy khách kiểm tra tính phù hợp của bộ nhớ đệm mà không cần tải lại dữ liệu. Theo HTTP Archive (2025), khoảng 40% tất cả các phản hồi HTTP là 304 Not Modified nhờ cấu hình ETag và Last-Modified phù hợp.

ETag được sử dụng ở đâu

ETag được sử dụng trong REST API để tối ưu hóa việc tải các bộ sưu tập dữ liệu — nếu danh sách đối tượng không thay đổi, máy khách nhận được 304 mà không cần truyền toàn bộ JSON. Đối với các tệp tĩnh (CSS, JS, hình ảnh), ETag cho phép CDN và trình duyệt kiểm tra hiệu quả tính mới của bộ nhớ đệm. Trong các ứng dụng di động, ETag rất quan trọng cho đồng bộ nền: ứng dụng kiểm tra xem dữ liệu trên máy chủ đã thay đổi chưa và tải xuống các bản cập nhật chỉ khi cần thiết. Điều này tiết kiệm băng thông và pin thiết bị.

ETag hoạt động như thế nào?

Vòng đời đầy đủ của ETag bao gồm bốn bước. Máy chủ tạo ETag ở yêu cầu đầu tiên và trả về nó trong tiêu đề phản hồi. Máy khách lưu ETag cùng với tài nguyên đã lưu trong bộ nhớ đệm. Khi yêu cầu lặp lại, máy khách gửi tiêu đề If-None-Match với giá trị ETag đã lưu. Máy chủ so sánh giá trị nhận được với ETag hiện tại của tài nguyên: nếu khớp, nó trả về 304 Not Modified với nội dung rỗng; nếu không khớp, nó trả về 200 OK với tài nguyên mới và ETag mới.

http
// Yêu cầu máy khách với If-None-Match
GET /api/users HTTP/1.1
Host: example.com
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

// Phản hồi máy chủ — tài nguyên không thay đổi
HTTP/1.1 304 Not Modified
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"

Trong một ứng dụng di động, chu trình này có thể được triển khai thông qua một trình khách HTTP hỗ trợ bộ nhớ đệm. Ví dụ, OkHttp tự động quản lý ETag thông qua CacheInterceptor: nó lưu ETag phản hồi và thêm If-None-Match trong các yêu cầu lặp lại. Khi nhận được 304, OkHttp trả về dữ liệu đã lưu trong bộ nhớ đệm. OkHttp hỗ trợ ETag mà không cần cấu hình thêm — chỉ cần bật bộ nhớ đệm qua OkHttpClient.Builder.cache().

Tạo ETag phía máy chủ

Máy chủ có thể tính ETags theo nhiều cách khác nhau: thông qua hash MD5 hoặc SHA của nội dung, thông qua số lần sửa đổi từ cơ sở dữ liệu (ví dụ: updated_at từ MySQL), thông qua sự kết hợp inode + mtime + kích thước cho các tệp tĩnh (Nginx tạo ETags theo cách này). Đối với API động, hash nội dung là đáng tin cậy nhất: nếu phản hồi JSON thay đổi dù chỉ một trường, ETag sẽ thay đổi. Tuy nhiên, tính toán hash cho mỗi yêu cầu gây tải cho CPU — đối với các hệ thống có tải cao, tốt hơn nên sử dụng số phiên bản tăng dần.

ETag mạnh và yếu

RFC 7232 định nghĩa hai loại ETags: mạnh (strong) và yếu (weak). ETag mạnh có nghĩa là hai biểu diễn của tài nguyên giống hệt nhau từng byte — không một bit nào khác biệt. ETag yếu (tiền tố W/) chỉ đảm bảo sự tương đương về mặt ngữ nghĩa: nội dung có thể khác ở mức tuần tự hóa (khoảng trắng, thứ tự trường JSON), nhưng dữ liệu được coi là giống nhau đối với máy khách. ETag yếu được đánh dấu bằng tiền tố W/, ví dụ W/"1a2b3c".

Việc lựa chọn loại ETag phụ thuộc vào yêu cầu về độ chính xác so sánh. Đối với các tệp tĩnh (CSS, JS, hình ảnh), ETag mạnh được ưu tiên hơn — nếu tệp đã thay đổi, máy khách phải nhận được phiên bản mới. Đối với API động, nơi cùng một JSON có thể được tuần tự hóa với thứ tự trường hoặc định dạng khác nhau, ETag yếu cung cấp tính linh hoạt hơn: máy chủ tạo ETag dựa trên dữ liệu kinh doanh thay vì biểu diễn chuỗi.

Loại ETagĐịnh dạngBảo đảmỨng dụng
Strong (mạnh)"hash"Giống nhau từng byteTệp tĩnh, tài nguyên nhị phân
Weak (yếu)W/"hash"Tương đương ngữ nghĩaAPI JSON, trang động

Một hạn chế của ETag yếu: chúng không thể được sử dụng với yêu cầu phạm vi (Range requests). Nếu máy khách yêu cầu một phần của tệp, máy chủ phải trả về ETag mạnh để đảm bảo rằng đoạn đó tương ứng với tài nguyên đầy đủ. ETag yếu không cung cấp sự đảm bảo đó. Trong các tình huống khác, ETag yếu an toàn và được khuyên dùng cho các API.

ETag vs Last-Modified

ETag và Last-Modified là hai tiêu đề HTTP cho các yêu cầu có điều kiện thường được sử dụng cùng nhau. Last-Modified cho biết ngày sửa đổi lần cuối của một tài nguyên và hoạt động với tiêu đề If-Modified-Since. ETag cung cấp một định danh phiên bản duy nhất và hoạt động với If-None-Match. Mỗi loại có ưu điểm và hạn chế riêng, và việc kết hợp chúng mang lại hiệu quả bộ nhớ đệm tối đa.

Last-Modified đơn giản hơn để triển khai — máy chủ tự động lấy ngày từ hệ thống tệp hoặc cập nhật trường updated_at trong cơ sở dữ liệu. Tuy nhiên, ngày có độ chính xác ở mức giây, không đủ cho các tài nguyên thay đổi nhiều lần mỗi giây. Ngoài ra, Last-Modified không phân biệt các trạng thái khác nhau: nếu một tệp bị ghi đèn với cùng phiên bản, ngày thay đổi nhưng nội dung không thay đổi, do đó máy khách sẽ tải lại dữ liệu giống hệt.

ETag chính xác hơn: nó chỉ thay đổi khi nội dung thực sự thay đổi. Nếu máy chủ khôi phục phiên bản trước đó từ bản sao lưu, ETag thay đổi. Nếu một tệp bị ghi đèn với cùng dữ liệu, ETag giữ nguyên và máy khách không tải lại. Sử dụng kết hợp được khuyên bởi đặc tả HTTP: máy chủ trả về cả hai tiêu đề, máy khách gửi If-None-Match và If-Modified-Since đồng thời. Nếu ít nhất một tiêu đề cho thấy sự thay đổi, máy chủ trả về tài nguyên mới.

Ưu tiên tiêu đề

Theo đặc tả, ETag có quyền ưu tiên hơn Last-Modified. Nếu máy chủ nhận được If-None-Match, nó chỉ nên kiểm tra ETag, bỏ qua If-Modified-Since. Điều này ngăn chặn các điều kiện cạnh tranh: nếu tài nguyên thay đổi giữa lúc máy khách gửi Last-Modified và kiểm tra trên máy chủ, ETag sẽ là chỉ báo mới hơn. Trong thực tế, các máy chủ thường kiểm tra cả hai tiêu đề, nhưng khi kết quả không khớp, ETag thắng thế.

Triển khai ETag phía máy chủ

Cấu hình ETag phụ thuộc vào loại máy chủ. Nginx tự động tạo ETags cho các tệp tĩnh dựa trên inode, mtime và kích thước. Apache sử dụng cơ chế FileETag. Đối với các ứng dụng động trên Node.js, PHP, Python, Ruby, ETags cần được tạo theo chương trình — thông qua hash phản hồi, số phiên bản dữ liệu hoặc kết hợp các tham số yêu cầu.

go
func etagMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter,
        r *http.Request) {
        // Tạo ETag dựa trên dữ liệu
        etag := generateETag(r.URL.Path)
        w.Header().Set("ETag", etag)

        // Kiểm tra If-None-Match
        if r.Header.Get("If-None-Match") == etag {
            w.WriteHeader(http.StatusNotModified)
            return
        }
        next.ServeHTTP(w, r)
    })
}

Middleware trong Go chặn yêu cầu, tạo ETag cho URL được yêu cầu (ví dụ, tính toán hash dữ liệu từ bộ nhớ đệm hoặc DB) và đặt tiêu đề phản hồi. Nếu máy khách đã gửi If-None-Match và nó khớp với ETag hiện tại, máy chủ trả về ngay 304 Not Modified mà không gọi trình xử lý chính. Trong môi trường sản xuất, nên thêm bộ nhớ đệm cho các ETag đã tính theo URL và tham số để giảm tải cho máy chủ.

Vấn đề và cạm bẫy

Trong cấu hình nhiều máy chủ (round-robin hoặc anycast), ETag phải giống nhau trên tất cả các nút cho cùng một tài nguyên. Nếu ETag được tạo dựa trên inode của tệp và trang web được triển khai trên nhiều máy chủ, các giá trị sẽ khác nhau. Giải pháp là sử dụng hash nội dung hoặc kho lưu trữ phiên bản tập trung (Redis, etcd). Vấn đề thứ hai là nén gzip: Nginx thay đổi ETag khi bật nén, có thể gây ra các phản hồi 304 dư thừa. Cần cấu hình gzip_vary on để đồng bộ ETag với nội dung đã nén.

Câu hỏi thường gặp

ETag có thể giống nhau cho các tài nguyên khác nhau không?

Có, nếu máy chủ không ngăn chặn điều này một cách rõ ràng. ETag không cần phải duy nhất trên toàn cầu — nó duy nhất trong một URL cụ thể. Đối với các tệp tĩnh, xung đột khó xảy ra khi sử dụng hash SHA, nhưng các trình tạo tùy chỉnh có thể tạo ra các bản sao trùng lặp.

Tôi có cần cấu hình ETag cho mọi tài nguyên không?

ETag hiệu quả nhất cho các tài nguyên được yêu cầu nhiều lần và ít khi thay đổi: tài sản tĩnh, danh sách API, cấu hình. Đối với các trang duy nhất được tải một lần (ví dụ: trang xác nhận đơn hàng), ETag không mang lại lợi ích.

ETag hoạt động với CDN như thế nào?

CDN xem xét ETag trong các yêu cầu nguồn để kiểm tra tính mới của bộ nhớ đệm. Nếu ETag của một tài nguyên trên nguồn thay đổi, CDN tải phiên bản mới. Cloudflare và Fastly hỗ trợ ETag như một cơ chế vô hiệu hóa bộ nhớ đệm tiêu chuẩn ở cấp độ nguồn.

ETag có thể dài hơn 255 ký tự không?

RFC 7232 không giới hạn độ dài ETag, nhưng các máy chủ và proxy có thể cắt bớt hoặc bỏ qua các giá trị quá dài. Nên sử dụng hash 20–40 ký tự hoặc kết hợp định danh phiên bản và tổng kiểm tra.

Nên chọn ETag hay Cache-Control?

Đây không phải là các cơ chế loại trừ lẫn nhau. Cache-Control xác định chính sách bộ nhớ đệm (lưu trong bao lâu, ai được phép), trong khi ETag là cơ chế xác thực cho các tài nguyên đã lưu trong bộ nhớ đệm. Cấu hình tối ưu bao gồm cả hai tiêu đề cùng nhau.

Tóm tắt

  • ETag — một tiêu đề HTTP với định danh phiên bản tài nguyên duy nhất cho các yêu cầu có điều kiện và bộ nhớ đệm hiệu quả
  • Nguyên tắc — máy khách gửi If-None-Match với ETag đã lưu, máy chủ phản hồi 304 nếu khớp
  • ETag mạnh — giống nhau từng byte cho tệp tĩnh, yếu — tương đương ngữ nghĩa cho API
  • ETag chính xác hơn Last-Modified — theo dõi nội dung, không phải ngày, và chỉ thay đổi khi có sửa đổi thực tế
  • Sử dụng kết hợp với Last-Modified mang lại hiệu quả bộ nhớ đệm tối đa
  • Phía máy chủ — tạo qua hash nội dung, số phiên bản dữ liệu hoặc kết hợp tham số
  • Khuyến nghị — sử dụng ETag cho tất cả các điểm cuối API và tài nguyên tĩnh trong ứng dụng di động

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm