Только что удалось, кажется, более-менее правильно победить давно мучающую читателей "Учебника" проблему, которую на днях снова озвучили.

Проблема, казалось бы, дурацкая и простая, но вот не давалась долгое время. Пишу этот пост-мортем, чтобы мне рассказали, как это сделать еще лучше, и чтобы это потом поисковиками находилось.

Итак, есть статические .html, .css и .js файлы, которые выдаются в неправильной кодировке. Если точнее, они выдаются с сервера вообще без кодировки: ни в самом файле не прописана, ни сервер (lighttpd) ее не выдает. Браузер, соответственно, гадает что-то в области ISO-8859-1, и получается ерунда.

Самое главное для меня — решить эту проблему с минимальной стоимостью поддержки. Проще говоря, чтобы я больше про это никогда не вспоминал.

Вариант прописывания <meta ... > в файл отпадает, потому что а) про это надо вспоминать в каждом новом файле, б) это не работает для стилей и скриптов.

И вот с научением lighttpd выдавать кодировку я и мучился по сю пору. Там за это отвечает директива mimetype.assign, в которой должно быть что-то вроде:

mimetype.assign = (
    ".html" => "text/html; charset=utf-8",
    ".css" => "text/css; charset=utf-8",
    ...
)

Однако в Ubuntu'вской сборке lighttpd эта настройка выглядит вот так:

include_shell "/usr/share/lighttpd/create-mime.assign.pl"

Она вызывает скрипт, который генерит большой маппинг для кучи типов, читая его из /etc/mime.types. В этом файле никаких кодировок быть не может, потому что он не предназначен исключительно для HTTP, это просто карта именно mime-типов, а не заголовков.

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

В итоге пришел к такому решению. Вывод скрипта сдампил в файл /etc/lighttpd/conf-available/mimetypes и отредактировал там строчки для .htm, .html, .css, .js, подписав к ним "; charset=utf-8". В своем локальном конфиге прописал include этого файла:

$HTTP["host"] =~ "(www.softwaremaniacs.org|softwaremaniacs.org)" {
  include "conf-available/mimetypes"
  ...
}

Поскольку конфиг локальный, пакет lighttpd про него ничего не знает и трогать при обновлениях не будет.

Еще замечу, что важно прописать его именно под условием, а не глобально, потому что иначе lighttpd будет ругаться, что эта настройка — дубликат той, которая так никуда и не делась из системного конфига.

Комментарии: 14 (особо ценных: 1)

  1. david-m.livejournal.com

    text/plain тогда уж добавьте, а вообще — все text/*

  2. Игорь Давыденко

    Для стилей отлично работает директива,

    @charset 'utf-8';
    

    перед первым правилом. Для скриптов же да, с кодировкой может быть проблема.

    зы. Больше про @charset: http://www.w3.org/International/questions/qa-css-charset

  3. barbuza

    за это нелюблю убунту и дебиан - жосткие любители испоганить родные конфиги и чего-нить автоматизировать.

  4. EXSlim

    в lighttpd есть отличная фича — поддержка замечательного lua. Ваша проблема решается простым скриптом:

    if (string.match(lighty.env["physical.rel-path"], ".css")) then
    lighty.header["Content-Type"] = "text/css; charset=utf-8"

  5. Mm

    Вопрос не в тему - а почему lighttpd, а не nginx?
    Есть какие-то производственные показатели?

  6. Антон

    Ой как все сложно в lighttpd. В nginx все это делается одной опцией в любом месте конфига.

  7. Dyadya Zed

    @Антон:

    Ой, не надо про простоту ngingx'a! Попробуйте установить кодировку UTF-8 для html'a, который будет отображаться на ошибку 404.

  8. Иван Сагалаев

    Ребят, а причем тут вообще nginx? Пост про решение одной частной мелкой проблемы с участием разного софта, а не про веб-серверы в целом.

  9. david-m.livejournal.com

    Сдаётся мне, проблема общая — в том, что настроенный конфиг веб-сервера может ни с того ни с сего переписаться дефолтным.

    И стоило бы как-то решить её, а не мелко фиксить последствия…

  10. Иван Сагалаев

    В Ubuntu (в Debian точнее) эта проблема как раз решена. Системные конфиги обычно пишутся так, чтобы include'ить юзерские конфиги из какой-нибудь директории. Именно поэтому у меня и получилось подпихнуть свою карту mime-типов в локальном юзерском конфиге.

    Другое дело, что просто синтаксис конфига lighttpd не подразумевает отдельного понятия "charset". Отсюда сложности.

  11. Alexander Lyabah

    Спасибо, заюзал )

  12. GQ

    Особо ценный комментарий

    Я бы при такой постановке сделал следующее:

    • заменил оригинальный скирпт на wrapper при помощи dpkg-divert.
    • В скрипте-враппере пропускал бы вывод оригинального скрипта через фильтр, подставляющий charset.
  13. Иван Сагалаев

    Спасибо большое за dpkg-divert, не знал.

  14. umonkey

    Можно после include_shell прописать:

    mimetype.assign += (
      ".txt" => "text/plain; charset=utf-8",
      ".log" => "text/plain; charset=utf-8",
      ".yaml" => "text/plain; charset=utf-8",
    )
    

Добавить комментарий