Ajax и кириллические символы
Вопрос в том как правильно отправлять и получать данные с сервера в нужной кодировке. Несколько вводных замечаний:
- AJAX - это технология асинхронного (как вариант) приема передачи данных по HTTP протоколу.
- Основным объектным классом на стороне клиента, реализующим собственно функционал, является XMLHttpRequest.
- Объект данного класса поддерживает прием передачу данных только методами GET и POST HTTP протокола.
Тепрь разберемся подробнее:
Запрос к серверу методом GET. Как известно используя этот метод, все данные для сервера передаются в
URL запроса и через заголовки. Пример:
На сервере, в set_busy.php можно будет использовать конструкцию $_GET['status'] и аналогичные, чтобы получить значения переменных переданных в запросе. Но в URL нельзя передавать
кириллические символы. Для этого используются escape-последовательности. Escape последовательность это: знак '%' за ним код символа в выбранной
кодировке. В принципе вы можете таким образом передавать
символы в любой кодировке, единственным условием является то, что необходимо использовать escape последовательности. Важно также отметить 2 факта:
- Используя метод GET мы НЕ можем в явном виде указать кодировку с помощью заголовка вида Content-type text/html charset="windows-1251" , просто потому что ничего кроме параметров запроса (т.е. все переменные передаются напрямую в строке запроса) мы серверу не отправляем (никакого контента просто нет).
- Если говорить об AJAX то объект класса XMLHttpRequest, который как говорилось раньше и осуществляет прием / передачу данных, делает это только в кодировке UTF-8, т.е. если мы даже дадим ему передать наши данные в windows-1251, то он все равно перекодирует их в utf-8, однако я уже забегаю вперед, потому что это относится уже к POST запросам, где мы передаем данные и можем указать в заголовке их кодировку.
Для
перекодировки данных, вы можете написать собственные функции перевода в нужную вам кодировку, но намного удобнее и проще использовать уже имеющиеся
JavaScript функции:
- escape()
- encodeURI()
- encodeURIComponent()
все три функции оставляют латинские и некоторые другие символы без изменений, все остальные символы заменяют
escape-последовательностями. функция escape() - переводит
кириллические символы в Unicode, при этом получаются символы вида %xx, либо %uxxxx, где xxxx - код символа именно в
Unicode НЕ в UTF-8. Поскольку реализация этой функции слишком зависит от броузера, использовать ее не рекомендуется. функция encodeURI() - переводит
кириллические символы в
UTF-8, латинские символы и символы
, / ? : @ & = + $ # остаются без изменений. функция encodeURIComponent() - переводит
кириллические символы в
UTF-8, латинские символы и символы !*()'
остаются без изменений. Именно эта функция, кстати, одобрена W3C и используется в библиотеках jQuery и prototype.js
для подготовки AJAX запросов. Итог: Чтобы передать серверу данные (с
кириллическими символами) методом GET нам необходимо предварительно перекодировать эти данные вышеуказанными функциями (лучше в
UTF-8). Эту процедуру скрыто от нас и делают библиотеки jQuery и prototype.js при подготовке GET запросов. На серверной стороне получив эти данные нам, как правило, необходимо будет перекодировать их в удобоваримую для нас
windows-1251, для этого можно использовать, функции
PHP:
- функция iconv: $status = iconv('UTF-8', 'windows-1251', $_GET['status']);
- либо, если установлен модуль mb_string, то функцию mb_convert_encoding, получаем приблизительно следующее: $status = mb_convert_encoding($_GET['status'], 'CP-1251', 'UTF-8');
Кстати, в PHP механизм работает так, потому что при получении запроса и формировании массива $_GET интерпретатор уже понимает escape - последовательности, и мы работаем в массивах со строками в определенной кодировке без всяких проблем.
Запрос к серверу методом POST. Для начала, что такое
POST? Это метод в котором сначала передаются заголовки в том числе и определяющие тип содержимого (контента), а затем передается сам контент в виде потока байт. Заголовок определяющий тип контента:
Content-type. С помощью этого заголовка можно передать не только сам тип данных, но и например, их кодировку. Так, если мы говорим об обработке запроса на стороне сервера на
PHP, то в зависимости от Content-type PHP заполняет либо массив $_POST и / или переменную $HTTP_RAW_POST_DATA. Массив $_POST PHP заполняет в том случае, когда в Content-type указано multipart/form-data или x-www-form-urlencoded. Почему же в этих случаях заполняется массив и каким образом, если мы говорили, что фактически контент это поток байт. Все просто, на самом деле указав эти виды Content-type, мы в качестве контента должны будет передать данные в виде пар: <параметр>=<значение>, объединенных знаком &. Т.е. практически как в GET, но с указанием кодировки и без ограничения на длину строки запроса в 255 символов, которая существует в GET. Пример контента для передачи методом POST, с указанными выше Content-type: p=qwerty&g=asdf, получив запрос, с таким контентом PHP сформирует массив $_POST, состоящий из двух элементов с ключами p, q и соответствующими им значениями. А если нужно передать не набор параметров, а просто текстовый или бинарный контент, в этом случае нужно использовать Content-type text/xml или application/octet-stream, и там же устанавливаем charset="windows-1251", в этом случае переданные данные попадают
на стороне сервера с PHP в переменную $HTTP_RAW_POST_DATA. Что же происходит, когда мы отправляем наши данные в
windows-1251 с помощью
AJAX - POST запроса? А происходит, то о чем я говорил выше объект класса XMLHttpRequest переводит контент в кодировку UTF-8 и только потом отправляет на сервер. После чего на стороне сервера нужно не забыть перевести эти данные в нужную нам кодировку (как правило windows-1251), упомянутыми выше функциями. И последний вопрос, а как в этом случае поступают библиотеки
jQuery и prototype.js? А поступают они точно также как и раньше они для формирования контента используют перекодировку функцией encodeURIComponent().
Ответ сервера на AJAX запрос. Для того чтобы ответ сервера на ваш
AJAX запрос был передан броузеру (клиенту) в правильной кодировке, нужно перед отправкой данных послать заголовок Content-type с указанием типа данных и их кодировки. Например, функцией PHP: header('Content-type: text/html; charset=windows-1251');
Общие выводы.
- Напрямую через объект класса XMLHttpRequest передаются символы только в UTF-8.
- Можно передавать строки в любых других кодировках, если нелатинские символы при этом заменены escape последовательностями.
- В JavaScript существует 3 функции, которые делают escape замену нелатинских символов: escape(), encodeURI() и encodeURIComponent().
- На стороне сервера полученные по AJAX данные как правило нужно перекодировать функциями iconv или mb_convert_encoding
- Перед отправкой ответа клиенту, необходимо послать заголовок Content-type с указанием кодировки, в которой выдается ответ.
- Общая, обычная схема перекодировок в процессе работы с технологией AJAX следующая: клиент (броузер) делает запрос серверу и передает данные в UTF-8, сервер получает данные перекодирует в windows-1251, обрабатывает и выдает ответ клиенту в windows-1251. Это безусловно так, если ваши страницы написаны в windows-1251.