Почему на странице в случайных местах отображаются юникодные знаки вопроса?

Рейтинг: 1Ответов: 2Опубликовано: 03.05.2015

Сайт на Asp.Net MVC с использованием Razor. Периодически в случайных местах встречаются вот такие знаки вопроса, при этом остальной русский текст отображается нормально.

Юникодный знак вопроса на странице

Положение и этих знаков зависит от контента страницы: если контент перед знаком изменится хоть на байт, знак либо исчезнет, либо переместится. Если контент до этого знака не изменяется, то он стабильно показывается при каждом обновлении страницы. Очевидно, что он появляется при какой-то деформации двухбайтовых символов. В кодировках везде выставлен UTF-8.

Есть предположение, что по каким-то причинам байты портятся на стыке двух TCP-пакетов. Я знаю, что TCP-протокол транспортного уровня, обеспечивающий целостность и непрерывность данных на верхнем уровне, но другого объяснения я не нашел. Как и не нашел причины, почему TCP может портить стыки пакетов.

Проблема проявляется на разных серверах с одним и тем же сайтом (перевозил пару раз), и даже на разных сайтах, созданных независимо друг от друга с нуля из стандартных шаблонов.

UPD

Пример поломанной строки: Не обработ�н.

Байты этой же строки:

0xD0, 0x9D, 0xD0, 0xB5, 0x20, 0xD0, 0xBE, 0xD0, 0xB1, 0xD1, 0x80, 0xD0, 0xB0, 0xD0, 0xB1, 0xD0, 0xBE, 0xD1, 0x82, 0xB0, 0xD0, 0xBD, 0x0A

Здесь видно, что в первом случае буква "а" кодируется 0xD0, 0xB0, а во втором (поломанном) случае 0xB0, 0xD0. Байты по каким-то причинам поменялись местами.

Ответы

▲ 2

Такое может быть вызвано некорректной реализацией HttpResponse.Filter (самописного, или готового стороннего).

Код подключения фильра обычно выглядит как

Response.Filter = new MyFilter(Response.Filter);

Проверить наличие фильтра можно под отладчиком - посмотреть тип текущего значения Response.Filter.

ASP.NET пишет респонс в фильтр кусками через метод:

public override void Write(byte[] buffer, int offset, int count)
{
    ...
}

и если фильтр не знает про юникод - то он обрабатывает куски "как есть", разрезая их на средине символа.

UPD: проблема так же можнет быть вызвана одним из уже исправленных багов в New Relic Browser Monitoring:

.NET Agent 2.25.208.0:

Fixes a problem where Unicode characters were not being correctly written to the page in some cases when Browser Monitoring was enabled in the agent.

.NET Agent 4.1.134.0:

Fixed a bug that caused the .NET agent to corrupt some non-HTML resources if browser monitoring was enabled.

Стоит обновить агента до последней версии.

▲ 1

Такая ситуация возникает, когда две проблемы с кодировкой частично компенсируют друг друга.

Допустим, файл у вас написан в кодировке utf-8. Но при этом Razor читает его как windows-1251. В итоге получается белиберда, однако эта белиберда оказывается "в целом корректна", за исключением тех символов, которые не причитались. Потом белиберда отдается в кодировке же windows-1251 браузеру, в котором срабатывает автоматическое определение кодировки по сигнатуре, и те же самые байты показываются вам уже в кодировке utf-8. Итог - Вы видите исходный текст, за исключением символов, потерянных при преобразованиях.

Проверьте кодировку на всех этапах: в каком виде она хранится в файле (правильная кодировка должна находиться в секции system.web/globalization вашего web.config). Проверяйте поведение всяческих промежуточных прокси-серверов, если таковые есть. Ну и конечно же проверьте, совпадает ли отданная серверов в заголовках кодировка с той, которую определил браузер.