Ajax и кириллические символы
Написал: admin в категорию Ajax, PHP, Программирование, tags: Ajax, Content-type, Javascript, jQuery, PHP, кириллица, перекодировки, ПрограммированиеВопрос в том как правильно отправлять и получать данные с сервера в нужной кодировке.
Несколько вводных замечаний:
- AJAX - это технология асинхронного (как вариант) приема передачи данных по HTTP протоколу.
- Основным объектным классом на стороне клиента, реализующим собственно функционал, является XMLHttpRequest.
- Объект данного класса поддерживает прием передачу данных только методами GET и POST HTTP протокола.
Тепрь разберемся подробнее:
Запрос к серверу методом GET.
Как известно используя этот метод, все данные для сервера передаются в URL запроса и через заголовки. Пример:
| GET
Host |
http://localhost/site1/set_busy.php?status=Free&servID=12&duration=0
localhost |
| User-Agent | Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.1.16) Gecko/20080702 Firefox/2.0.0.16 |
| Accept | */* |
| Accept-Language | ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3 |
| Accept-Encoding | gzip,deflate |
| Accept-Charset | windows-1251,utf-8;q=0.7,*;q=0.7 |
| Keep-Alive | 300 |
| Connection | keep-alive |
| X-Requested-With | XMLHttpRequest |
| Referer | http://localhost/site1/index.php?userID=6 |
| Cookie | PHPSESSID=48a6861e659a87904d3a1d07958d8227 |
На сервере, в 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.
Записи (RSS)
Blog…
http://web-accent.com/ajax-i-kirillicheskie-simvoly.html/...
Спасибо, полезная статья. Проблемы с кодировками на каждом шагу блин. UTF-8 толко добавляет проблем нам…
Спасибо за информацию о функциях JavaScript, делающих escape-замену. Особенно интересно было узнать о функции encodeURI(), т.к. часто приходится сталкиваться с проблемой перевода строк именно в UTF-8 из других кодировок.
Зачетный пост, спасибо!