Как генерируются и настраиваются ETag?

Я недавно прошел через концепцию ETag HTTP заголовок. ( это) Но у меня все еще есть проблема, что для конкретного ресурса HTTP, который отвечает за генерацию ETag?

Другими словами, это реальное приложение, контейнер (например, Tomcat), веб-сервер / балансировщик нагрузки (например, Apache/Nginx)?

Может кто-нибудь, пожалуйста, помогите?

1 ответ

Решение

Как и с большинством аспектов спецификации HTTP, ответственность в конечном итоге лежит на том, кто предоставляет ресурс.

Конечно, часто в этом случае мы используем инструменты - серверы, балансировщики нагрузки, платформы приложений и т. Д. - которые помогают нам выполнять эти обязанности. Но нет никакой спецификации, определяющей, что должен предоставлять "веб-сервер", в отличие от приложения, это просто практический вопрос о том, какие функции доступны в используемых вами инструментах.

Теперь, глядя на ETags в частности, общая ситуация заключается в том, что инфраструктура или веб-сервер могут быть сконфигурированы для автоматического хеширования ответа (либо тела, либо чего-то еще) и размещения результата в ETag, Затем, на условный запрос, он сгенерирует ответ и хэширует его, чтобы увидеть, изменился ли он, и автоматически отправит условный ответ, если он не изменился.

Чтобы взять два примера, с которыми я знаком, nginx может сделать это со статическими файлами на уровне веб-сервера, а Django может сделать это с динамическими ответами на уровне приложения.

Такой подход распространен, прост в настройке и работает довольно хорошо. Однако в некоторых ситуациях он может не подходить для вашего случая использования. Например:

  • Чтобы вычислить хеш для сравнения с входящим ETag сначала вы должны получить ответ. Таким образом, хотя условный ответ может сэкономить ваши накладные расходы при передаче ответа, он не может сэкономить затраты на генерацию ответа. Так что если генерация вашего ответа стоит дорого, и у вас есть альтернативный источник ETags (например, номера версий, хранящиеся в базе данных), вы можете использовать это для достижения лучшей производительности.
  • Если вы планируете использовать ETags чтобы предотвратить случайные перезаписи с помощью методов с изменением состояния, вам, вероятно, потребуется добавить собственный код приложения, чтобы сделать вашу логику сравнения и установки атомарной.

Так что в некоторых ситуациях вы можете захотеть создать свой ETags на уровне приложения. Чтобы снова взять Django в качестве примера, он предоставляет вам простой способ предоставить собственную функцию для вычисления ETags,

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

Обзор типичных алгоритмов, используемых в веб-серверах. Допустим, у нас есть файл с

  • Размер 1047, т.е. 417 в шестиграннике.
  • MTime, т.е. последняя модификация в понедельник, 6 января 2020 г., 12:54:56 по Гринвичу, что составляет 1578315296 секунд по времени unix или 1578315296666771000 наносекунд.
  • Inode - физический номер файла 66, т.е. 42 в шестнадцатеричном формате.

Различные веб-серверы возвращают ETag как:

  • Nginx: "5e132e20-417" т.е. "hex(MTime)-hex(Size)". Не настраивается.
  • BusyBox httpd такой же, как Nginx
  • Apache / 2.2: "42-417-59b782a99f493" т.е. "hex(INode)-hex(Size)-hex(MTime in nanoseconds)". Можно настроить, но MTime все равно будет в нано
  • Apache/2.4: "417-59b782a99f493" т.е. "hex(Size)-hex(MTime in nanoseconds)" т.е. без INode, который удобен для балансировки нагрузки, когда один и тот же файл имеет разные INode на разных серверах.
  • OpenWrt uhttpd: "42-417-5e132e20" т.е. "hex(INode)-hex(Size)-hex(MTime)". Не настраивается.
  • Tomcat 9: W/"1047-1578315296666" т.е. Weak"Size-MTime in milliseconds". Это неправильный ETag, потому что он должен быть сильным, как для статического файла, то есть восьмеричной совместимости.
  • LightHTTPD: самое странное: "hashcode(42-1047-1578315296666771000)" т.е. INode-Size-MTimeно затем уменьшено до простого целого числа с помощью хэш-кода. Можно настроить, но можно отключить только одну часть (etag.use-inode = "disabled")
  • MS IIS: имеет вид Filetimestamp:ChangeNumber, например, "53dbd5819f62d61:0". Не задокументировано, не настраивается, но может быть отключено.
  • Причал: на основе последнего мода, размера и хеширования. См. Resource.getWeakETag()
  • Китура (Свифт): "W/hex(Size)-hex(MTime)" StaticFileServer.calculateETag

Немного мыслей:

  • Здесь так часто используются шестнадцатеричные числа, потому что преобразовать десятичное число в более короткую шестнадцатеричную строку дешево.
  • Inode при добавлении дополнительных гарантий делает балансировку нагрузки невозможной и очень хрупкой, если вы просто скопировали файл во время повторного развертывания приложения.MTime в наносекундах доступно не на всех платформах, и такая детализация не требуется.
  • У Apache есть ошибка по этому поводу, например https://bz.apache.org/bugzilla/show_bug.cgi?id=55573
  • Приказ MTime-Size или Size-MTime также имеет значение, потому что MTime с большей вероятностью изменится, поэтому сравнение строки ETag может быть быстрее для десятка циклов ЦП.
  • Даже если это не полный хэш контрольной суммы, но определенно не слабый ETag. Этого достаточно, чтобы показать, что мы ожидаем восьмеричной совместимости для запросов Range.
  • Apache и Nginx разделяют почти весь трафик в Интернете, но большинство статических файлов передаются через Nginx, и его нельзя настроить.

Похоже, что Nginx использует наиболее разумную схему, поэтому, если вы ее реализуете, попробуйте сделать ее такой же. Весь ETag, сгенерированный на C, с одной строкой:

printf("\"%" PRIx64 "-%" PRIx64 "\"", last_mod, file_size)

Я предлагаю взять схему Nginx и сделать ее рекомендованным W3C алгоритмом ETag.

Другие вопросы по тегам