Python / PHP / JavaScript developer
0,0
рейтинг
16 октября 2011 в 16:19

Разработка → «Правильная» utf-8 кодировка в настройках nginx/apache

Надеюсь, что данный пост окажется полезным многим разработчикам, т.к. судя по многочисленным тредам в интернете, проблема-то довольно частая. Суть проблемы в следующем: неправильное наименование кодировки utf-8 в настройках nginx/apache. При этом отдаваемый сервером контент воспринимается нормально во всех браузерах, кроме Internet Explorer-a.



Зачастую, многие разработчики, при конфигурации виртуальных хостов копируют настройки откуда-нибудь из интернета или же из других мест. И при этом в их настройки «перекочевывает» ошибка. В случае nginx это директива:
charset utf8;

В случае Apache это:
<Directory /path/to/site/>
AddDefaultCharset UTF8
</Directory>

Так вот — нет такой кодировки как utf8! Правильно писать utf-8 (через дефис). Большинство браузеров (Firefox >= 3, Opera >= 9, Chrome >= 4, Safari >= 4) лояльно относятся к указанию utf8 в качестве кодировки, и воспринимают отдаваемый контент корректно, а вот все версии Internet Explorer (включая даже последнюю, 9ую) вместо контента выдают «кракозябры». Конечно же эта ситуация легко обходится даже без исправления настроек web-сервера. Так, например, в случае отдачи динамического контента с использованием PHP, можно явно указывать кодировку в самом скрипте:
header('Content-type: text/html; charset=utf-8');

Или же использовать в HTML следующий тег:
<meta http-equiv="content-type" content="text/html; charset=utf-8" />

И все бы хорошо, но ситуация усложняется когда посредством AJAX JavaScript пытается достучаться до статического контента. Пример с использованием jQuery:
$(document).ready(function(){
    function print_r()
    {
      //...
    }
    $.ajax({
        url: "/test.txt",
        dataType: "text",
        success: function(data, textStatus){
            $('#res').html(data);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            $('#res').html('jqXHR: ' + print_r(jqXHR) + '<br />textStatus: ' + textStatus + '<br />errorThrown: ' + print_r(errorThrown));
        }
    });
});

В данном случае IE выдает ошибку следующего характера:
{
  jqXHR: {
    readyState: 4,
    status: 0,
    statusText: 'error'
  },
  textStatus: 'error',
  errorThrown: {
     name: 'Error',
     number: -1072896658,
     description: 'Не удалось завершить действие. Ошибка c00ce56e.',
     message: 'Не удалось завершить действие. Ошибка c00ce56e.'
  }
}

Данная JS ошибка достаточно нетривиальна. И если пользователи, кто уже сталкивался с подобным, сразу сообразят в чем дело, то у тех, кто сталкивается с подобным впервые, может возникнуть недоумение и уйти много времени на выяснение причины.

P.S. Как было верно подмечено в комментариях, при обращении к MySQL для указания в какой кодировке обращаться к БД используется запрос:
SET NAMES utf8

Да и вообще везде, где идет ссылка на кодировку utf-8, например при создании таблицы:
CREATE TABLE `some_table` (… ) ENGINE=innoDB DEFAULT CHARSET=utf8

кодировка указывается utf8, а не utf-8. То есть в данном случае запись идет БЕЗ дефиса, что вносит ещё больший когнитивный диссонанс в понимание происходящего…
Дмитрий @StraNNikk
карма
48,0
рейтинг 0,0
Python / PHP / JavaScript developer
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (72)

  • +34
    Так вот оно что) Оказывается не во всех грехах виноват IE)
    • НЛО прилетело и опубликовало эту надпись здесь
      • +47
        Лояльность в отношении трактовки стандартов ни к чему хорошему, как правило, не приводит ;)
        • +4
          Да? Т.е. надо сразу после встретившейся ошибки упасть на бок или выдать грозное сообщение, которое простому пользователю ни о чем не говорит? Есть известные распространенные ошибки, и хороший браузер должен как можно более прозрачно для пользователя постараться их исправить. Да, в какой-то мере это способствует распространению этих ошибок. Но с другой стороны пользователь не имеет возможности повлиять на содержимое/настройки посещаемого сайта/сервера. А посему лично я бы предпочел тот браузер, который корректно отобразит наибольшее количество страниц, несмотря на ошибки в них.
          • +2
            Кстати, разработчики стандартов сами ошибки допускают, которые потом вынужденно копируются теми, кто по этому стандарту работает. Яркий тому пример поле referer при том, что правильно было бы referrer.
          • +22
            Раньше IE много ругали за то, что он слишком мягко относится к стандартам, сейчас ругают за то, что следует им. Не угодишь.
            • +3
              то что он совсем не следует одним стандартам не противоречит тому, что он слишком строго следит за другими :)
            • –2
              Я ИЕ в данном случае не ругаю, что вы. Я говорю, что из двух браузеров я выберу тот, который лучше отобразит ошибочные страницы.
              • +3
                IE ровно поэтому и мягко относился к стандартам. Но сейчас важно им следовать. Слишком быстро веб прошлого превратился в ад из-за такого отношения.
                • –2
                  Ответьте на простой вопрос: что лучше — выдать ошибку, с которой посетитель сайта ничего не может поделать, т.к. не контролирует посещаемый ресурс, или попытаться отобразить по какой-то определенной логике?

                  Я не говорю о том, что надо нарушать стандарты стандарты, я говорю о том, что надо гибко обходить ошибки. Пользователь прежде всего!

                  Я вам приведу такой пример отвлеченный, чтобы легче было ответить: попадается вам битый архив (или упакованный с нарушением стандарта). Какая реализация архиватора будет лучше: та, которая попытается распаковать архив или та, которая выдаст кучу матюков и пошлет пользователя куда подальше?
                  • +4
                    Отвечаю: лучше следовать стандарту.

                    Вспомните как раньше IE пытался ориентироваться не на mime type, а на содержимое. Ничего хорошего из этого не вышло. Туда же можно отнести уязвимость с UTF-7.
                    • 0
                      Мне думается, что плохую имплементацию и нарушение стандартов нельзя складывать в одну кучу с расширением стандартов. Не знаю, как еще эту мысль можно донести. Но ваше право предпочитать негибкое ПО :)
                  • +1
                    Лучше выдать ошибку, это поможет правильно настроить сервер (указать правильную кодировку в конфиге).
                    • 0
                      Как это поможет _посетителю_?
                      • 0
                        Это поможет администратору сервера обнаружить ошибку, а не списывать всё на глюки браузера.
                      • 0
                        _Посетитель_ придет на сайт, разработанный по жестким стандартам и отлаженный на этапе разработки.
                        Я не имею в виду, что разработчикам ИЕ прямо сейчас надо «дергать рубильник», отключающий самостоятельность поведения. Этот рубильник не надо было трогать еще тогда, в самом начале своего пути.
                        • 0
                          И где бы тогда был Microsoft.

                          Вообще история веба началась с самовольного впиливания в HTML не включенного в стандарт тега IMG… Правда мелкософт тут не причем.

                          Другая древняя история с полями в див, когда Microsoft сделали отображение % в дивах как логично, а не как написано. Что весьма доставляло дизайнерам в 6ом эксполрере. А в итоге с 7 эксплорером, где микрософтовцы извинились, покаялись и «сделали всё обратно» куча резинового дизайна «поехало».
                      • +1
                        до посетителя такая ошибка попросу не дойдёт ибо будет замечена гораздо раньше выкладки на продакшен.
                      • 0
                        Посетитель, ошибки не увидит, её раньше заметит веб-разработчик, погуглит, найдет эту статью и сообщит администратору сервера, что у него не все в порядке с настройками.
                  • +1
                    Странно, почему программеры на сях, яве и т.д. никогда не парились на тему ошибок из-за собственной криворукости. Есть ошибка — надо править. Задолбали, право слово.
                • –2
                  И еще, ИЕ не мягко относился к стандартам, он их прямо нарушал, отсюда ад. А вот добавление еще одного нестандартного алиаса к кодировке ничего плохого не несет в себе. Все браузеры имеют собственные расширения стандартов, и это нормально. Считайте utf8 — проприетарным расширением стандарта. Да, ие не обязан ему следовать, но раз ошибка распространена, то, учитывая это, можно сделать программу более дружественной по отношению к пользователю, который сможет-таки увидеть нужный ему контент.
                  • +2
                    И еще, ИЕ не мягко относился к стандартам, он их прямо нарушал, отсюда ад. А вот добавление еще одного нестандартного алиаса к кодировке ничего плохого не несет в себе.
                    Конечно, и определение содержимого не по mime type — тоже ничего плохого, правда? Зато пользователю покажем всё как надо.
                    • 0
                      Вопрос лишь в нарушении стандартов. Если оно есть, значит это плохо. Если нарушения нет, то зависит от надежности алгоритма и качества имплементации. Если сделано качественно, то это только плюс софту.
                      • 0
                        Отдельно хочу написать слово минусаторам: посетите на досуге вот этот урл: validator.w3.org/check?uri=http%3A%2F%2Fhabrahabr.ru%2Fblogs%2Fwebdev%2F130511%2F&charset=%28detect+automatically%29&doctype=Inline&group=0 (теги у меня не пролезают на хабр, поэтому таким образом размещаю).

                        Прикиньте, если бы браузер начал брыкаться, метериться и отказался бы в итоге загрузить хабрахабр? Вы бы выкинули его и поставили другой, который был бы не таким капризным к ошибкам, или перестали бы посещать Хабр?
                        • +3
                          Хабрапрограммеры исправили бы.
                          • 0
                            Да это не важно, я не об этом. На хабре куча несоответствий XHTML 1.0 Transitional, но браузеры именно благодаря терпимости к ошибкам отображают сайт без проблем, и почему-то никто не возмущается таким их поведением. А вот поддержка utf8 (вместо utf-8) почему-то определена оппонентами как «зло». Двойные стандарты? :)
        • 0
          Но ни что не мешает браузеру сообщать об ошибках на странице человеческим языком.
  • +5
    IE в данном случае как раз действует ровно в соответствии со стандартными названиями кодировок (http://www.iana.org/assignments/character-sets). См. также статью IE9 Compatibility: Proper Use of the Charset Token от Eric Lawrense
  • +24
    wtf8
    • 0
      wtf-8!
  • –3
    Удивительно.
    У меня есть сервера которые устанавливались еще в далеком 2008 году. Где кодировка выставлено верно, а именно URF-8.

    Хотелось бы узнать в каких дистрибутивах автор нашел подобное неверное обозначение кодировки.
    • +29
      > верно, а именно URF-8.
      действительно, не подкопаться.
      • –11
        Объясните, это шутка юмора такая?
        Я уже начал думать, что у меня сильные пробелы в знаниях, Гугл уверено предлагает поискать про UTF-8.
        • 0
          Ну да, это типа ирония была.
          Из контекста же понятно.
      • 0
        Дайте пожалуйста ссылку на URF-8 — я совершенно серьёзно не смог найти, запрос предлагают сменить на UTF-8 и всё.
    • +1
      В смысле «в каких дистрибутивах»? Речь идет о дистрибутивах Linux? они-то тут причем?
      Данное поведение имеет место независимо от дистрибутива, и зависит от того, какие настройки прописаны в виртуальных хостах.

      • 0
        Именно. Только если вы возьмете исходники апача вы там уведите верное определение кодировки.
        А это означает, что появление НЕВЕРНОГО описания кодировки на совести того кто собирал дистрибутив (из которого взят был пакет), или конфигурировал сам апач в ручную, изменив значение по умолчанию с верного на неверное.
        • 0
          Проблема не в исходниках того или иного веб-сервера, тут исходники вообще не причем. Да и nginx и apache отрабатывают верно — к ним претензий нет. Проблема в том, что люди зачастую в настройках виртуальных хостов сами вручную указывают неверную кодировку, даже не подозревая об этом (просто скопировав откуда-нибудь из примеров, коих бесчисленное множество в интернете, и в последствии при разработке возникают нетривильные ошибки
          • –4
            Простите еще раз. Когда Вы что то ставите из исходников, к ним в обязательном порядке идет и конфиг. Чтобы сделать сейчас неправильно — нужно залезть и исправить с правильного на неправильное.

            Вот мне и стало интересно, где кто сто столкнулся с этой абсурдной ситуацией.

            • 0
              то есть у вы пользуетесь только дефолтными конфигами?
              абсолютно не могу такое представить в отношении веб-серверов :)
            • 0
              Все очень просто: Эникейщик взял, скопипастил, а в конфиги даже не смотрел.
            • 0
              Ненене… кажется, вы неправильно понимаете. Конфиг компиляции — это одно, а конфиг виртуального хоста — это другое. После того как веб-сервер скомпилялся, надо же настроить на какую директорию он будет смотреть, какой хост (домен) цеплять и т.п. И именно за это и отвечает конфиг виртуального хоста. А кодировка по-умолчанию, насколько мне известно, вообще не прописывается даже в тестовых виртуальных хостах.
            • 0
              А вот вам статистика. Я собирал материалы для доклада и пробежал спайдером по 200 тыс. сайтов в рунете. Помимо нужных мне данных собрал и кодировки из заголовков.

              И вот, при правильном написании windows-1251 и UTF-8 мне встретились:

              win-1251
              windows1251
              windows_1251
              x-cp1251
              windows-cp1251
              unicode
              utf8
              UTF
              

              Более редкие случаи связаны с неправильным аргументом в функции, формирующие заголовок Content-type:

              =utf-8
              cp-1251>charset=windows-1251
              

              Особо ушлый товарищ выдал такое:

              koi8-r/windows-1251
              

              Мол, выбирайте по вкусу.

              Короче, итог такой: из всей выборки 2.43% сайтов неправильно отдают charset. Конкретно по utf8 — 0.27% из всех вариантов написания кодировки UTF-8.
    • 0
      Зачастую, многие разработчики, при конфигурации виртуальных хостов копируют настройки откуда-нибудь из интернета или же из других мест. И при этом в их настройки «перекочевывает» ошибка.

      Вы не внимательно читаете.
  • 0
    IE также не понимает cp1251 прописанным в htaccess. Как раз на днях столкнулся с этим, вообще никак не хотело реагировать на jQuery, изменил на windows-1251 и все проблемы исчезли
  • +3
    1) Масштабные ошибки в документации встречаются сплошь и рядом. Скажем, вспоминается, что не только в документации (точнее FAQ) nginx, но даже в дефолтном (который идет в комплекте с системой!!!) htaccess, который поставляется в комплекте Drupal — дается некорректный конфиг для SEO-урлов, из-за которого без корректировки не будут работать мультиязычные сайты. Ошибка черте сколько времени кочует туда-обратно…

    2) Не надо приставать особо к IE. Он стал жертвой обстоятельств. :-) Впору вообще писать топик про ошибки Файрфокса, некоторые из которых существуют годами и хрен бы кто их исправил… Скажем, попробуйте абсолютно отпозиционировать элемент внутри fieldset с position:relative. Все браузеры, включая IE6, не имеют с этим никаких проблем, а вот FF косячит. Вот буквально на днях вроде наконец поправили и в FF10 все станет нормально… Но, блин, IE6, которому больше 10 лет этого косяка не имеет!
    • 0
      >1. Drupal. Здесь суть не в том что ошибка обнаружена, а в том был ли запостен багфикс в багтрекер или нет. Может просто разработчики незнают о нем потому как не пользуются мультиязычными сайтами (ну чисто теоретически). И надо им в этом помочь
  • 0
    IE6 на Windows XP Pro & SP2 тут ни каких кракозябр не показывает (хотя IE ох как любит ставить по дефолту windows-1251). Скажите, дохтур, что я делаю не так?
    • 0
      эм… вот только что проверил на своей виртуалке в IE6 (который ставится по дефолту в WinXP). Бага воспроизводится: bit.ly/r6nWRe. Ну и вот тут можно проверить: ipinfo.info/netrenderer/ через online-эмуляцию IE.
      • 0
        Виртуалки это конечно неплохо, но у меня нативная установка и бага в ней нет. Что лично мне позволяет усомниться в наличие оного. Нам нужен еще один пользователь без виртуалок который может зайти на урл.
      • 0
        Так, проверили на Windows 7 с IE 9.0.8112 и так крокозябры таки да, имеются. Я же на своем 6.0.2900.2180.xpsp_sp2_rtm ни чего подобного не наблюдаю. Учитывая, что это не дефольтный у меня браузер, а чисто для тестов, то и настроек в нем ни когда не подкручивал.
        • +1
          странная ситуация :) быть может в SP2 идут какие-то неофициальные фиксы 6ого ишака?
          • 0
            Тут даже не знаю, это интегрированный SP2 он шел при инсталяции ОСи изначально. В общем нужно пособирать статистику с других IE по возможности, хотя думается SP2 в наше время уже не откопать.
  • +3
    Кстати, добавлю пару замечаний. Во-первых, писать header(Content-Type) в PHP — это быдлокод, надо просто в конфиг PHP вписать default_mimetype и default_charset. Во-вторых, несмотря на то, что кодировка называется utf-8, при работе с MySQL, ее надо писать (в конфиге и в переменных типа SET NAMES) в виде utf8 — как не странно.

    А разработчики ИЕ все делают в этот раз правильно.
    • 0
      Про header(Content-Type) согласен, но в контексте данной статьи это имелось ввиду в качестве примера, в том плане, что кодировку можно выставлять не через web-сервер а посредством самого интерпритатора.
      Про MySQL опять же согласшусь, и надо сказать это вносит ещё большую путанницу o_O
  • +10
    StraNNikk, дай тебя расцелую!!!
    Блин, я всю голову сломал с одним проектом, который у меня напрочь отказывался аяксовые запросы делать в IE хрен знает сколько времени убил на то, чтобы найти ошибку.
    А тут бац, зашел на хабр, тут статья. Поставил дефис, все заработало! Ну это ппц вообще, я в шоке. :) Еще раз спасибо, жаль кармы нет тебе плюсиков наставить((((
    • +3
      всегда пожалуйста! ;-) а про плюсики… никакие плюсики не заменят ощущение того, что статья принесла кому-то реальную пользую! ;-)
      • 0
        И от меня спасибо тоже, правда появись эта статья на 3 дня раньше цены б ей небыло. а то какраз эта ошибка вывкакивала, но нарыл уже в других местах.
        Еще по дури вылазила у меня ошибка с ajax.response (Firefox, Chrome — нормально работали ) а вот ИЕ в обязательном порядке требовал responseText.
        И еще Firefox Chrome нормально отрабатывают такой код:
        tbl = document.createElement('table')
        tbl.innerHTML = ''

        А ИЕ в этом случае выдает ошибку так как наверное хочет чтоб ему делали таблицу в DOM-е а не на чистом HTML
    • 0
      К слову у меня вот это использовалось jqueryui.com/demos/tabs/ и я долго не мог понять почему пример взятый с сайта работает в IE, а после того как я перенес к себе в проект не работает. Оказалось в одном модуле, который вообще не я писал (шаблонизатора) стояло как раз utf8 и никого не трогало, не где не проявлялось, пока я не решил добавить ajax формочек. Вот там-то и всплыл этот баг с IE, при чем ошибка выдавалась стандартная аяксовая, по типу «не могу загрузить и все тут». А из миллиона причин та что с utf8 я бы наверное проверил последней.
  • 0
    Разница между utf-8 и utf8, кстати, не только в контексте браузеров присутствует. В моём любимом языке программирования Perl между ними вообще коренные различия, хотя кто бы ожидал такого от лишнего тире…
    • +1
      Не тире — дефисоминуса.
      • 0
        Дефис и минус тоже сильно отличаются.
        • 0
          В общем дефис это.
        • 0
          Да, конечно; но тут-то речь не о дефисе (x2010) и не о минусе (x2212), и тем более не о тире (x2014), а о простом дефисоминусе, который у нас на клавиатурах (x002D).
  • 0
    Или же использовать в HTML следующий тег:
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />

    А я-то думал браузеры-то на него давно забили и кодировку выставляют исключительно (кроме случаев ручного выбора) как раз согласно тому, что сообщил сервер в header-е http-ответа. Неужели нет?
    • –1
      ммм… нет. а почему браузеры должны были на него забивать? как раз этот тег позволяет «рулить» кодировками независимо от того, что ответил сервер в заголовках. А если говорить точнее, то значения данного тега имеют наивысший приоритет при выборе заголовков ответа от сервера.
      • +1
        значения данного тега имеют наивысший приоритет

        Что-то не замечал, вроде на практике получалось наоборот. Спасибо, полезно знать. Поэкспериментирую.
        • +1
          Наивысший приоритет имеет заголовок СЕРВЕРА. На HTML тег браузер смотрит только если сервер ничего ему не выдает.
          • –1
            да, точняк — с наивысшим приоритетом я перегнул палку. Значение HTTP-заголовка превалирует над значением META-тегов только в случае, когда заголовок не понятен или же при ненормальном статус коде (!=200) и не у всех заголовков.
  • +3
    Забавно, порылся поиском по содержимому своего сервера, нашёл «utf8» в PHP скриптах WordPress
    wp-config-sample.php
    /** Кодировка базы данных для создания таблиц. */
    define('DB_CHARSET', 'utf8');

    Вот может откуда ноги у ошибок растут, браузерам надо одно написание, а БД другое.
  • 0
    Автор, добавьте, что в MySQL запросах нужно писать utf8, а то щас ломанутся все исправлять свой «set names utf8» на «set names utf-8»
    • +1
      Добавил!

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