ETag (Entity Tag) — μια κεφαλίδα HTTP που εκχωρεί ένα μοναδικό αναγνωριστικό της έκδοσης ενός πόρου στον διακομιστή, επιτρέποντας στον πελάτη να ελέγχει αποτελεσματικά την επικαιρότητα των αποθηκευμένων στην κρυπτή μνήμη δεδομένων. Σε μια επαναληπτική αίτηση, ο φυλλομετρητής ή η εφαρμογή στέλνει το αποθηκευμένο ETag, και ο διακομιστής το συγκρίνει με το τρέχον: σε περίπτωση αντιστοιχίας, επιστρέφεται η κατάσταση 304 Not Modified χωρίς σώμα απάντησης. Σύμφωνα με το RFC 7232 (IETF, 2014), οι υπό προϋποθέσεις αιτήσεις με ETag μειώνουν τον όγκο των μεταδιδόμενων δεδομένων έως και 95% για πόρους που ζητούνται συχνά. Αυτό καθιστά την κεφαλίδα κρίσιμη για την απόδοση των κινητών εφαρμογών.
Βασικά σημεία
ETag (Entity Tag) — είναι μια κεφαλίδα απάντησης HTTP που περιέχει ένα μοναδικό αναγνωριστικό μιας συγκεκριμένης έκδοσης πόρου. Ο διακομιστής υπολογίζει το ETag βάσει του περιεχομένου του αρχείου, των μεταδεδομένων του ή του αριθμού αναθεώρησης και το μεταβιβάζει στον πελάτη στην απάντηση σε μια αίτηση GET. Ο πελάτης αποθηκεύει αυτό το αναγνωριστικό και σε επόμενες αιτήσεις προς τον ίδιο πόρο το στέλνει στην κεφαλίδα If-None-Match. Αν ο πόρος δεν έχει αλλάξει, ο διακομιστής απαντά με 304 Not Modified, και ο πελάτης χρησιμοποιεί το αποθηκευμένο στην κρυπτή μνήμη αντίγραφό του.
Η μορφή του ETag ορίζεται στο RFC 7232 ως συμβολοσειρά σε εισαγωγικά: "33a64df551425fcc55e4d42a148795d9f25f89d4". Η τιμή μπορεί να είναι ένα hash SHA-1 του περιεχομένου του αρχείου, ένας αυξητικός αριθμός έκδοσης, ένας συνδυασμός inode-αριθμός-χρόνος για στατικά αρχεία ή ένα οποιοδήποτε token που δημιουργείται από τον διακομιστή. Η μοναδική απαίτηση είναι η τιμή να αλλάζει σε κάθε αλλαγή του πόρου και να μην αλλάζει αν ο πόρος παραμένει ο ίδιος.
Το ETag ανήκει στους μηχανισμούς υπό προϋποθέσεις αιτήσεων (conditional requests) — μία από τις βασικές βελτιστοποιήσεις του πρωτοκόλλου HTTP. Σε αντίθεση με τις ανόρυσιμες αιτήσεις, όπου ο διακομιστής επιστρέφει πάντα μια πλήρη απάντηση, μια υπό προϋποθέσεις αίτηση επιτρέπει στον πελάτη να ελέγχει την επικαιρότητα της κρυπτής μνήμης χωρίς να κατεβάσει ξανά τα δεδομένα. Σύμφωνα με τα δεδομένα HTTP Archive (2025), περίπου 40% όλων των απαντήσεων HTTP είναι 304 Not Modified χάρη στη σωστή ρύθμιση του ETag και του Last-Modified.
Το ETag χρησιμοποιείται σε REST API για βελτιστοποίηση της φόρτωσης συλλογών δεδομένων — αν η λίστα αντικειμένων δεν έχει αλλάξει, ο πελάτης λαμβάνει 304 χωρίς να στέλνει ολόκληρο το JSON. Σε στατικά αρχεία (CSS, JS, εικόνες) το ETag επιτρέπει σε CDN και προγράμματα περιήγησης να ελέγχουν αποτελεσματικά την επικαιρότητα της κρυπτής μνήμης. Σε κινητές εφαρμογές, το ETag είναι κρίσιμο για συγχρονισμό παρασκηνίου: η εφαρμογή ελέγχει αν τα δεδομένα στον διακομιστή έχουν αλλάξει και κατεβάζει ενημερώσεις μόνο όταν χρειαστεί. Αυτό εξοικονομεί εύρος ζώνης και μπαταρία συσκευής.
Ο πλήρης κύκλος λειτουργίας του ETag αποτελείται από τέσσερα βήματα. Ο διακομιστής δημιουργεί το ETag στην πρώτη αίτηση και το επιστρέφει στην κεφαλίδα απάντησης. Ο πελάτης αποθηκεύει το ETag μαζί με τον αποθηκευμένο στην κρυπτή μνήμη πόρο. Σε μια επαναληπτική αίτηση, ο πελάτης στέλνει την κεφαλίδα If-None-Match με την τιμή του αποθηκευμένου ETag. Ο διακομιστής συγκρίνει την ληφθείσα τιμή με το τρέχον ETag του πόρου: σε περίπτωση αντιστοιχίας, επιστρέφει 304 Not Modified με κενό σωματίδιο, σε περίπτωση ασυμφωνίας — 200 OK με νέο πόρο και νέο ETag.
// Αίτηση πελάτη με If-None-Match
GET /api/users HTTP/1.1
Host: example.com
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
// Απάντηση διακομιστή — ο πόρος δεν άλλαξε
HTTP/1.1 304 Not Modified
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Σε μια κινητή εφαρμογή, αυτός ο κύκλος μπορεί να υλοποιηθεί μέσω ενός πελάτη HTTP με υποστήριξη κρυπτής μνήμης. Το OkHttp, για παράδειγμα, διαχειρίζεται αυτόματα το ETag μέσω CacheInterceptor: αποθηκεύει το ETag της απάντησης και σε μια επαναληπτική αίτηση προσθέτει If-None-Match. Κατά τη λήψη 304, το OkHttp επιστρέφει τα αποθηκευμένα στην κρυπτή μνήμη δεδομένα. Το OkHttp υποστηρίζει το ETag χωρίς επιπλέον ρύθμιση — αρκεί η ενεργοποίηση της κρυπτής μνήμης μέσω OkHttpClient.Builder.cache().
Ο διακομιστής μπορεί να υπολογίζει το ETag με διαφορετικούς τρόπους: μέσω hash MD5 ή SHA του περιεχομένου, μέσω του αριθμού αναθεώρησης από τη βάση δεδομένων (π.χ. updated_at από MySQL), μέσω του συνδυασμού inode + mtime + size για στατικά αρχεία (το Nginx δημιουργεί ETag ακριβώς με αυτόν τον τρόπο). Για δυναμικά API, το πιο αξιόπιστο είναι το hash περιεχομένου: αν η απάντηση JSON άλλαξε έστω ένα πεδίο, το ETag θα αλλάξει. Ωστόσο, ο υπολογισμός του hash σε κάθε αίτηση επιβαρύνει την CPU — για συστήματα υψηλής φόρτωσης είναι καλύτερο να χρησιμοποιείται αυξητικός αριθμός έκδοσης.
Το RFC 7232 ορίζει δύο τύπους ETag: ισχυρά (strong) και ασθενή (weak). Ένα ισχυρό ETag σημαίνει ότι δύο αναπαραστάσεις του πόρου είναι ταυτόσημες byte-προς-byte — κανένα bit δεν διαφέρει. Ένα ασθενές ETag (πρόθεμα W/) εγγυάται μόνο σημασιολογική ισοδυναμία: το περιεχόμενο μπορεί να διαφέρει σε επίπεδο σειριοποίησης (διαστήματα, σειρά πεδίων JSON), αλλά τα δεδομένα θεωρούνται ίδια για τον πελάτη. Τα ασθενή ETag σημειώνονται με πρόθεμα W/, π.χ. W/"1a2b3c".
Η επιλογή του τύπου ETag εξαρτάται από τις απαιτήσεις ακρίβειας σύγκρισης. Για στατικά αρχεία (CSS, JS, εικόνες) προτιμούνται τα ισχυρά ETag — αν το αρχείο έχει αλλάξει, ο πελάτης πρέπει να λάβει τη νέα έκδοση. Για δυναμικά API, όπου το ίδιο JSON μπορεί να σειριοποιηθεί με διαφορετική σειρά πεδίων ή μορφοποίηση, τα ασθενή ETag παρέχουν περισσότερη ευελιξία: ο διακομιστής δημιουργεί το ETag βάσει επιχειρηματικών δεδομένων, όχι της συμβολοσειράς.
| Τύπος ETag | Μορφή | Εγγύηση | Εφαρμογή |
|---|---|---|---|
| Strong (ισχυρό) | "hash" | Ταυτότητα byte-προς-byte | Στατικά αρχεία, δυαδικοί πόροι |
| Weak (ασθενές) | W/"hash" | Σημασιολογική ισοδυναμία | JSON API, δυναμικές σελίδες |
Περιορισμός των ασθενών ETag: δεν μπορούν να χρησιμοποιηθούν με αιτήσεις εύρους (Range requests). Αν ο πελάτης ζητά ένα μέρος του αρχείου, ο διακομιστής πρέπει να επιστρέψει ένα ισχυρό ETag για να εγγυηθεί ότι το τμήμα αντιστοιχεί στον πλήρη πόρο. Τα ασθενή ETag δεν παρέχουν τέτοια εγγύηση. Σε άλλα σενάρια, τα ασθενή ETag είναι ασφαλή και συνιστώνται για API.
Το ETag και το Last-Modified είναι δύο κεφαλίδες HTTP για υπό προϋποθέσεις αιτήσεις που χρησιμοποιούνται συχνά μαζί. Το Last-Modified υποδεικνύει την ημερομηνία της τελευταίας τροποποίησης του πόρου και λειτουργεί με την κεφαλίδα If-Modified-Since. Το ETag παρέχει ένα μοναδικό αναγνωριστικό έκδοσης και λειτουργεί με If-None-Match. Κάθε ένα έχει τα πλεονεκτήματα και τους περιορισμούς του, και ο συνδυασμός παρέχει μέγιστη αποδοτικότητα αποθήκευσης στην κρυπτή μνήμη.
Το Last-Modified είναι απλούστερο στην υλοποίηση — ο διακομιστής λαμβάνει αυτόματα την ημερομηνία από το σύστημα αρχείων ή ενημερώνει το πεδίο updated_at στη βάση δεδομένων. Η ημερομηνία όμως έχει ακρίβεια έως ένα δευτερόλεπτο, κάτι που δεν είναι αρκετό για πόρους που αλλάζουν πολλές φορές ανά δευτερόλεπτο. Επιπλέον, το Last-Modified δεν διακρίνει διαφορετικές καταστάσεις: αν το αρχείο αντικατασταθεί με την ίδια έκδοση, η ημερομηνία αλλάζει, αλλά το περιεχόμενο όχι — ο πελάτης φορτώνει ξανά τα ίδια δεδομένα.
Το ETag είναι ακριβέστερο: αλλάζει μόνο σε πραγματική αλλαγή του περιεχομένου. Αν ο διακομιστής επανέφερε την προηγούμενη έκδοση από αντίγραφο ασφαλείας, το ETag θα αλλάξει. Αν το αρχείο αντικατασταθεί με τα ίδια δεδομένα — το ETag παραμένει το ίδιο, και ο πελάτης δεν θα φορτώσει ξανά. Η κοινή χρήση συνιστάται από την προδιαγραφή HTTP: ο διακομιστής επιστρέφει και τις δύο κεφαλίδες, ο πελάτης στέλνει If-None-Match και If-Modified-Since ταυτόχρονα. Αν τουλάχιστον μία κεφαλίδα εμφανίζει αλλαγή — ο διακομιστής επιστρέφει νέο πόρο.
Σύμφωνα με την προδιαγραφή, το ETag έχει προτεραιότητα έναντι του Last-Modified. Αν ο διακομιστής έλαβε If-None-Match, πρέπει να ελέγχει μόνο το ETag, αγνοώντας το If-Modified-Since. Αυτό αποτρέπει race condition: αν ο πόρος άλλαξε μεταξύ της αποστολής του Last-Modified από τον πελάτη και του ελέγχου στον διακομιστή, το ETag θα είναι ο πιο πρόσφατος δείκτης. Στην πράξη, οι διακομιστές συνήθως ελέγχουν και τις δύο κεφαλίδες, αλλά σε περίπτωση ασυμφωνίας αποτελεσμάτων κερδίζει το ETag.
Η ρύθμιση του ETag εξαρτάται από τον τύπο του διακομιστή. Το Nginx δημιουργεί ETag για στατικά αρχεία αυτόματα βάσει inode, mtime και μεγέθους. Το Apache χρησιμοποιεί τον μηχανισμό FileETag. Για δυναμικές εφαρμογές σε Node.js, PHP, Python, Ruby, το ETag πρέπει να δημιουργείται με προγραμματισμό — μέσω hash της απάντησης, αριθμού έκδοσης δεδομένων ή συνδυασμού παραμέτρων αίτησης.
func etagMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter,
r *http.Request) {
// Δημιουργία ETag βάσει δεδομένων
etag := generateETag(r.URL.Path)
w.Header().Set("ETag", etag)
// Έλεγχος If-None-Match
if r.Header.Get("If-None-Match") == etag {
w.WriteHeader(http.StatusNotModified)
return
}
next.ServeHTTP(w, r)
})
}
Η middleware Go προϋποκλέπτει την αίτηση, δημιουργεί ETag για το URL που ζητήθηκε (π.χ. υπολογίζει hash δεδομένων από την κρυπτή μνήμη ή τη βάση δεδομένων) και ορίζει την κεφαλίδα απάντησης. Αν ο πελάτης έστειλε If-None-Match και ταιριάζει με το τρέχον ETag, ο διακομιστής επιστρέφει αμέσως 304 Not Modified, χωρίς να καλείται ο κύριος handler. Σε παραγωγικό περιβάλλον, αξίζει να προστεθεί αποθήκευση στην κρυπτή μνήμη των υπολογισμένων ETag ανά URL και παραμέτρους για τη μείωση του φόρτου του διακομιστή.
Σε μια πολυδιακομιστική διάμορφωση (round-robin ή anycast) το ETag πρέπει να είναι το ίδιο σε όλους τους κόμβους για τον ίδιο πόρο. Αν το ETag δημιουργείται βάσει του inode του αρχείου και η ιστοσελίδα λειτουργεί σε πολλά διακομιστές, οι τιμές θα διαφέρουν. Η λύση — χρήση hash περιεχομένου ή κεντρικής αποθήκευσης εκδόσεων (Redis, etcd). Το δεύτερο πρόβλημα — συμπίεση gzip: το Nginx αλλάζει το ETag όταν η συμπίεση είναι ενεργή, κάτι που μπορεί να προκαλέσει υπερβολικά 304. Απαιτείται η ρύθμιση gzip_vary on για συγχρονισμό του ETag με συμπιεσμένο περιεχόμενο.
Συχνές ερωτήσεις
Ναι, εάν ο διακομιστής δεν το απέτρεψε ρητά. Το ETag δεν χρειάζεται να είναι παγκόσμια μοναδικό — είναι μοναδικό εντός ενός συγκεκριμένου URL. Για στατικά αρχεία, οι συγκρούσεις είναι απίθανες όταν χρησιμοποιείται hash SHA, αλλά για σπιτικούς γεννήτορες είναι πιθανά διπλότυπα.
Το ETag είναι πιο αποτελεσματικό για πόρους που ζητούνται πολλές φορές και σπάνια αλλάζουν: στατικά αρχεία, λίστες API, ρυθμίσεις. Για μοναδικές σελίδες που φορτώνονται μία φορά (π.χ. σελίδα επιβεβαίωσης παραγγελίας), το ETag δεν παρέχει πλεονέκτημα.
Το CDN λαμβάνει υπόψη το ETag σε αιτήσεις origin για έλεγχο της επικαιρότητας της κρυπτής μνήμης. Αν το ETag του πόρου στο origin άλλαξε, το CDN κατεβάζει τη νέα έκδοση. Cloudflare και Fastly υποστηρίζουν το ETag ως standard μηχανισμό ακύρωσης της κρυπτής μνήμης στο επίπεδο origin.
Το RFC 7232 δεν περιορίζει το μήκος του ETag, αλλά οι διακομιστές και τα proxy μπορεί να κόψουν ή να αγνοήσουν πολύ μακριές τιμές. Συνιστάται η χρήση hash με μήκος 20–40 χαρακτήρων ή συνδυασμός αναγνωριστικού έκδοσης με άθροισμα ελέγχου.
Αυτά δεν είναι αμοιβαία αποκλειόμενοι μηχανισμοί. Το Cache-Control καθορίζει την πολιτική αποθήκευσης στην κρυπτή μνήμη (πόσο να αποθηκεύεται, σε ποιον επιτρέπεται), ενώ το ETag είναι μηχανισμός επικύρωσης του αποθηκευμένου πόρου. Η βέλτιστη ρύθμιση περιλαμβάνει και τις δύο κεφαλίδες μαζί.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης