HTTP: создание заголовка ETag

Как создать HTTP-заголовок ETag для файла ресурсов?


person tags2k    schedule 07.08.2008    source источник


Ответы (7)


etag — это произвольная строка, которую сервер отправляет клиенту, которую клиент отправит обратно на сервер при следующем запросе файла.

etag должен вычисляться на сервере на основе файла. Вроде как контрольная сумма, но вы можете не захотеть проверять контрольную сумму каждого отправляемого файла.

 server                client
 
        <------------- request file foo
 
 file foo etag: "xyz"  -------->
 
        <------------- request file foo
                       etag: "xyz" (what the server just sent)
 
 (the etag is the same, so the server can send a 304)

Я построил строку в формате метка даты-размер файла-номер индексного дескриптора файла. Таким образом, если файл изменяется на сервере после того, как он был передан клиенту, вновь сгенерированный etag не будет совпадать, если клиент повторно запросит его.

char *mketag(char *s, struct stat *sb)
{
    sprintf(s, "%d-%d-%d", sb->st_mtime, sb->st_size, sb->st_ino);
    return s;
}
person Mark Harrison    schedule 07.08.2008
comment
Если mtime — это время последнего изменения файла, то для чего нужны размер и индексный дескриптор? - person Steve; 04.02.2010
comment
В моем случае это потому, что это был вычисленный путь из программы CGI. Вы правы, что в случае прямого пути mtime, вероятно, будет достаточно. Поскольку стоимость в основном будет в stat(), дополнительная плата за включение индексного дескриптора и размера не взимается, что может защитить от (конечно, весьма маловероятного) случая, когда мошеннический администратор может обновить файл и вернуться к нему. исходное время. - person Mark Harrison; 04.02.2010
comment
@MarkHarrison, зачем тебе двойные кавычки вокруг etag? Является ли это обязательной частью синтаксиса? - person Pacerier; 19.07.2012

Пока он меняется всякий раз, когда изменяется представление ресурса, то, как вы его создаете, полностью зависит от вас.

Вы должны попытаться произвести его таким образом, чтобы дополнительно:

  1. не требует повторного вычисления при каждом условном GET, и
  2. не меняется, если содержимое ресурса не изменилось

Использование хэшей контента может привести к ошибке №1, если вы не сохраните вычисленные хэши вместе с файлами.

Использование номеров инодов может привести к сбою в #2, если вы переупорядочите свою файловую систему или будете обслуживать контент с нескольких серверов.

Один из механизмов, который может работать, заключается в использовании чего-то, полностью зависящего от содержимого, например, хэш SHA-1 или строка версии, вычисляемая и сохраняемая один раз при изменении содержимого вашего ресурса.

person Justin Sheehy    schedule 09.08.2008

Из http://developer.yahoo.com/performance/rules.html#etags:

По умолчанию как Apache, так и IIS встраивают данные в ETag, что значительно снижает шансы на успех теста на достоверность на веб-сайтах с несколькими серверами.

...

Если вы не пользуетесь преимуществами гибкой модели проверки, предоставляемой ETag, лучше вообще удалить ETag.

person grom    schedule 07.08.2008

Как создать тег apache по умолчанию в bash

for file in *; do printf "%x-%x-%x\t$file\n" `stat -c%i $file` `stat -c%s $file` $((`stat -c%Y $file`*1000000)) ; done

Даже когда я искал что-то точно такое же, как etag (браузер запрашивает файл только в том случае, если он изменился на сервере), это никогда не работало, и я закончил использовать трюк GET (добавляя метку времени в качестве аргумента получения к файлам js ).

person lolesque    schedule 05.09.2011

Я использовал Adler-32 в качестве сокращателя html-ссылок. Я не уверен, что это хорошая идея, но пока я не заметил никаких дубликатов. Он может работать как генератор etag. И это должно быть быстрее, чем попытка хэширования с использованием схемы шифрования, такой как sha, но я этого не проверял. Код, который я использую:

 shortlink = str(hex(zlib.adler32(link)+(2**32-1)/2))[2:-1]
person peawormsworth    schedule 27.12.2012

Я бы рекомендовал не использовать их и вместо этого использовать заголовки с последними изменениями.

У Аскапача есть полезная статья на эту тему. (поскольку они делают почти все, что кажется!)

http://www.askapache.com/htaccess/apache-speed-etags.html

person Rich Bradshaw    schedule 19.09.2008
comment
Хм, это позор, надеюсь, они скоро вернутся, так как сайт был золотой жилой советов! - person Rich Bradshaw; 03.02.2010
comment
@RichBradshaw, просто вопрос: как мы можем узнать отметку времени последнего изменения ресурса? Это полностью ручная операция после просмотра истории изменений БД? Или есть какие-то автоматизированные способы? - person Supun Wijerathne; 28.11.2017

Пример кода Марка Харрисона аналогичен тому, что используется в Apache 2.2. Но такой алгоритм вызывает проблемы с балансировкой нагрузки, когда у вас есть два сервера с одним и тем же файлом, но файл inode отличается. Вот почему в Apache 2.4 разработчики упростили схему ETag и удалили часть inode. Также, чтобы сделать ETag короче, обычно они кодируются в шестнадцатеричном формате:

    
<inttypes.h>
    
    
char *mketag(char *s, struct stat *sb)
{
    sprintf(s, "\"%" PRIx64 "-%" PRIx64 "\"", sb->st_mtime, sb->st_size);
    return s;
}
    

или для Java

 etag = '"' + Long.toHexString(lastModified) + '-' +
                                Long.toHexString(contentLength) + '"';

для С#

// Generate ETag from file's size and last modification time as unix timestamp in seconds from 1970
public static string MakeEtag(long lastMod, long size)
{
    string etag = '"' + lastMod.ToString("x") + '-' + size.ToString("x") + '"';
    return etag;
}

public static void Main(string[] args)
{
    long lastMod = 1578315296;
    long size = 1047;
    string etag = MakeEtag(lastMod, size);
    Console.WriteLine("ETag: " + etag);
    //=> ETag: "5e132e20-417"
}

Функция возвращает ETag, совместимый с Nginx. См. сравнение ETag с разных серверов

person Sergey Ponomarev    schedule 26.07.2020