HTTP: создание заголовка ETag
Как сгенерировать HTTP-заголовок ETag для файла ресурсов?
6 ответов
Этаг - это произвольная строка, которую сервер отправляет клиенту, которую клиент отправит обратно на сервер при следующем запросе файла.
Этаг должен быть вычисляемым на сервере на основе файла. Вроде как контрольная сумма, но вы можете не захотеть проверять контрольную сумму каждого файла, отправляющего ее.
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_ino, sb-> st_mtime, sb-> st_size); возврат с; }
Пока оно меняется всякий раз, когда изменяется представление ресурса, то, как вы его создадите, полностью зависит от вас.
Вы должны попытаться произвести это способом, который дополнительно:
- не требует, чтобы вы пересчитывали его при каждом условном GET, и
- не меняется, если содержание ресурса не изменилось
Использование хэшей контента может привести к сбою в #1, если вы не сохраните вычисленные хэши вместе с файлами.
Использование номеров инодов может привести к сбою на #2, если вы переставляете файловую систему или обслуживаете контент с нескольких серверов.
Один из механизмов, который может работать, - это использовать что-то полностью зависимое от содержимого, такое как хэш SHA-1 или строка версии, вычисляемая и сохраняемая один раз при изменении содержимого вашего ресурса.
От http://developer.yahoo.com/performance/rules.html:
По умолчанию как Apache, так и IIS встраивают данные в ETag, что значительно сокращает вероятность успешного прохождения теста на веб-сайты с несколькими серверами.
...
Если вы не пользуетесь гибкой моделью валидации, предоставляемой ETag, лучше всего просто удалить ETag.
Как сгенерировать Apache ETAG по умолчанию в 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 (добавив метку времени в качестве аргумента get в файлы js).
Я использовал Adler-32 в качестве сокращения ссылок HTML. Я не уверен, что это хорошая идея, но пока я не заметил дубликатов. Это может работать как генератор etag. И это должно быть быстрее, чем пытаться хэшировать, используя схему шифрования, такую как sha, но я не проверял это. Код, который я использую:
shortlink = str(hex(zlib.adler32(link)+(2**32-1)/2))[2:-1]
Я бы порекомендовал не использовать их и использовать вместо них последние измененные заголовки.
У Askapache есть полезная статья на эту тему. (поскольку они делают почти все, что кажется!)
Пример кода Марка Харрисона аналогичен тому, что использовался в 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) + '"';
для C#
// 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 s с разных серверов