Jquery кодировка. AJAX и проблемы с кодировками. Теперь рассмотрим коротко POST
AJAX, - это технология. Одной из часто используемых техник этой технологии является посылка запросов при помощи объекта класса XMLHttpRequest.
Классов то, конечно, в JavaScript нет, но для удобства будем пользоваться такой терминологией.
В документации на XMLHttpRequest сказано, что браузер должен поддерживать следующие типы HTTP- запросов:
GET, POST, HEAD, PUT , DELETE, OPTIONS
На сегодняшний день джаваскриптом через объект класса XMLHttpRequest можно отправить только запросы типа GET и POST .
Итак, рассмотрим 2 этих запроса:
Вся информация скрипту на сервере может передаваться только через URL и через заголовки.
Host: moy-rebenok
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.1.11) Gecko/20071127
Firefox/2.0.0.11
Accept:
Text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/pn
G,*/*;q=0.5
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
Referer: http://moy-rebenok/ajax.html
На сервере, в ajax.php можно будет использовать конструкцию
$_GET["f"], чтобы получить значение переменной f.
Почему встает проблема с русскими буквами? Потому что, как вы знаете, русские буквы в URL использовать нельзя, их необходимо как-то передать при помощи доступных латинских букв, цифр и знаков, допустимых в URL после знака "?".
Люди договорились, что будут делать это при помощи escape-последовательностей.
escape последовательность слова "привет" в кодировке windows-1251:
%EF%F0%E8%E2%E5%F2
escape последовательность слова "привет" в кодировке UTF-8:
%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82
escape последовательность слова "привет" в кодировке KOI8-R:
%CE%CF%D5%C1%C5%D0
(Знак "%", потом код символа).
Таким образом передать русские буквы можно, например, так:
GET http://moy-rebenok/ajax.php?f=%EF%F0%E8%E2%E5%F2
GET http://moy-rebenok/ajax.php?f=%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82
Никто вас в этом не ограничивает .
Кстати, для GET запроса не нужно
указывать заголовок
Content-Type.
Т.к. никакого контента нет. Есть только запрос по определенному адресу.
Все переменные на сервер передаются через URL.
Как же смастерить необходимую escape последовательность в нужной кодировке?
Мастерить можно хоть руками, хоть как, но естественно в JavaScript.
Опять же, никто вас не ограничивает.
Но для удобства обычно используют одну из 3 функций, которые уже определены в JavaScript :
а) escape()
б) encodeURI()
в) encodeURIComponent()
По порядку:
Латинские буквы, цифры, символы @*/+. оставляет как есть, всё остальное кодирует так:
%xx, либо так: %uxxxx.
Причем, xxxx во втором случае, - это код символа не в UTF-8, а в Unicode
Использовать эту функцию не надо , т.к. результат выполнения зависит от браузера, функция не является стандартизированной W3C, возникла в лихие 90-е.
К тому же, как-то нормально (по крайней мере, быстро) обработать строку в таком винигретчатом формате на сервере сложно.
Функцию escape() использует библиотека нашего
соотечественника JsHttpRequest.
Не потому что библиотека плохая, а потому что создана для работы со всеми
браузерами
(в том числе и с самыми древними).
Латинские буквы, цифры, символы!@#$&*()=:/;?+". оставляет как есть, всё остальное
кодирует
Одобрено W3C.
в) encodeURIComponent():
Латинские буквы, цифры, символы!*()". оставляет как есть, всё остальное кодирует
escape-последовательностями в кодировке UTF-8.
Одобрено W3C.
Используется jQuery, prototype.js при запросе методом GET.
Возможно вы слышали от кого-то: "XMLHttpRequest работает
только с UTF-8".
Теперь знаете, что это не совсем правда.
Когда используется GET-запрос, то кодировка переданных данных вообще нигде не прописывается(!).
Ещё раз повторю, "Content-type", в котором мы можем указать charset не используется в GET запросах.
Но, т.к. в JavaScript есть 2 удобные функции для перевода любой строки в строку с escape-последовательностями в UTF-8, то все их используют, и работают с UTF-8.
Именно поэтому в jQuery даже нельзя никак указать charset при отправке запроса.
Именно поэтому в Prototype.js, даже когда указываешь encoding="windows-1251", и используешь GET запрос, то передается всё равно UTF-8.
Просто потому что в кодах этих библиотек используется функция encodeURIComponent().
Что ж. В этом нет совершенно ничего плохого. Всё, что надо сделать, чтобы теперь работать в PHP в нормальной кодировке использовать iconv:
$f = iconv("UTF-8", "windows-1251", $_GET["f"]);
Кстати, мы можем это сделать именно потому, что $_GET работает так, что он понимает
escape-последовательности. Спасибо создателям PHP.
Т.е. когда приходит GET запрос PHP смотрит на URL, создает
для нас массив $_GET, а мы
уже с ним что хотим, то и делаем. Но это вроде понятно должно быть.
2) POST-запросы.
Здесь уже всё интереснее.
Вот приходит это запрос на сервер. Обработчик PHP смотрит на Content-type, и в зависимости от него заполняет массив $_POST и/или переменную $HTTP_RAW_POST_DATA.
$_POST он заполняет в том случае, когда в Content-type указано multipart/form-data или
x-www-form-urlencoded.
Что-же это за Content-type такой?
А контент-тайп это очень удобный. Он позволяет передать php
скрипту несколько переменных.
Что по сути такое POST запрос?
Это заголовки, а за ними контент. Контент вообще произвольный. Т.е. просто байты, байты, байты.
Но ведь из JavaScript обычно требуется передать не просто байты, байты, байты, а несколько пар ключ=значение, ключ=значение, ...
Как в GET запросе.
Вот люди и договорились о таком удобном типе, как x-www-form-urlencoded
Для того, чтобы передать f=123 и gt=null необходимо передать контент:
Знакомо неправда ли? Конечно знакомо, и тип не зря называется x-www-form-urlencoded.
Всё то же самое, что и при GET запросе.
И как же формируется контент в библиотеках jQuery и
prototype.js?
Верно, при помощи всё той же функции encodeURIComponent(), а значит и escape-последовательности будут в кодировке UTF-8. (Независимо от того, что в prototype.js вы установите encoding).
Всё. Осталась ещё одна возможность. Ведь можно передавать
не x-www-form-urlencoded (т.е. не параметры), а обычный текстовый или бинарный
контент, который потом можно будет прочитать через $HTTP_RAW_POST_DATA.
Для этого устанавливаем Content
-type
text
/xml
или application
/octet
-stream
,
там же устанавливаем charset="windows-1251".
Засовываем в функцию send() строку нужной кодировки. (Prototype.js оборачивает этот вызов конструкцией new Ajax.Request(...)).
И что потом... А он (объект класса XMLHttpRequest) переводит эту строку в UTF-8, в какой бы кодировке она не была. Так написано в документации W3C. И он реально это делает.
Выводы:
2. Можно передавать строки как бы "в любых других кодировках", если нелатинские символы при этом за-escape-ены.
3. В JavaScript существует 3 функции, которые escape-ят нелатинские символы:
escape(), encodeURI() и encodeURIComponent().
Первая переводит в кривой Unicode. Вторые две в UTF-8.
Можно написать свои функции, которые будут генерировать escape-последовательности любой кодировки. Можно, но не нужно. Т.к. наоборот надо радоваться, что есть такие вот функции, которые переводят текст любой кодировки в UTF-8. Это черезвычайно прекрасный факт. Схема при которой все xhtml страницы работают на windows-1251, ajax с сервера клиенту кидает windows-1251, а ajax с клиента серверу кидает UTF-8 абсолютна приемлема и используется на большинстве ресурсов .
Просто не надо забывать использовать iconv как было описано ниже. А для того, чтобы сервер отдавал яваскрипту JSON (или что там у вас) в правильной кодировке (т.е. в такой же кодировке, в которой отдаются все xhtml страницы) просто в начале вашего ajax.php пропишите заголовок:
header("Content-type: text/html;
charset=windows-1251");
И всё будет ок.
На последок немного субъективного мнения:
Используйте jQuery, любите людей, дарите подарки.
AJAX, - это технология. Одной из часто используемых техник этой технологии является
посылка запросов при помощи объекта класса XMLHttpRequest.
Как же посылать и принимать AJAX запросы в нужной нам кодировке, нужно ли использовать однобайтовые кодировки или не обойтись без UTF-8. На все эти вопросы раз и навсегда ответит эта статья.
И ещё, классов-то, конечно, в JavaScript нет, но для удобства будем пользоваться такой терминологией.
В документации на XMLHttpRequest сказано, что браузер должен поддерживать следующие типы
HTTP-запросов: GET, POST, HEAD, PUT, DELETE, OPTIONS.
На сегодняшний день джаваскриптом через объект класса XMLHttpRequest можно отправить
только запросы типа GET и POST
.
Итак, рассмотрим 2 этих запроса:
Вся информация скрипту на сервере может передаваться только через URL и через заголовки.
На сервере, в ajax.php можно будет использовать конструкцию
$_GET["f"], чтобы получить значение переменной f.
Почему встает проблема с русскими буквами? Потому что, как вы знаете, русские буквы в URL использовать нельзя, их необходимо как-то передать при помощи доступных латинских букв, цифр и знаков, допустимых в URL после знака "?".
Люди договорились, что будут делать это при помощи escape-последовательностей.
Escape последовательность слова «привет» в кодировке windows-1251:
%EF%F0%E8%E2%E5%F2
Escape последовательность слова «привет» в кодировке UTF-8:
%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82
Escape последовательность слова «привет» в кодировке KOI8-R:
%CE%CF%D5%C1%C5%D0
(Знак "%", потом код символа).
Таким образом передать русские буквы можно, например, так:
Никто вас в этом не ограничивает .
Кстати, для GET запроса не нужно
указывать заголовок Content-Type.
Т.к. никакого контента нет. Есть только запрос по определенному адресу.
Все переменные на сервер передаются через URL.
Как же смастерить необходимую escape последовательность в нужной кодировке?
Мастерить можно хоть руками, хоть как, но естественно в JavaScript.
Опять же, никто вас не ограничивает.
Но для удобства обычно используют одну из 3 функций, которые уже определены в JavaScript:
А) escape()
б) encodeURI()
в) encodeURIComponent()
По порядку:
Латинские буквы, цифры, символы @*/+. оставляет как есть, всё остальное кодирует так:
%xx, либо так: %uxxxx.
Причем, xxxx во втором случае, - это код символа не в UTF-8, а в Unicode
Использовать эту функцию не надо , т.к. результат выполнения зависит от браузера, функция не является стандартизированной W3C, возникла в лихие 90-е.
К тому же, как-то нормально (по крайней мере, быстро) обработать строку в таком винигретчатом формате на сервере сложно.
Функцию escape() использует библиотека нашего соотечественника JsHttpRequest.
Не потому что библиотека плохая, а потому что создана для работы со всеми браузерами
(в том числе и с самыми древними).
Б) encodeURI()
Латинские буквы, цифры, символы!@#$&*()=:/;?+". оставляет как есть, всё остальное
кодирует
В) encodeURIComponent():
Латинские буквы, цифры, символы!*()". оставляет как есть, всё остальное кодирует
escape-последовательностями в кодировке UTF-8.
Одобрено W3C.
Используется jQuery, prototype.js при запросе методом GET.
Возможно вы слышали от кого-то: «XMLHttpRequest работает только с UTF-8».
Теперь знаете, что это не совсем правда.
Когда используется GET-запрос, то кодировка переданных данных вообще нигде не прописывается(!).
Ещё раз повторю, "Content-type", в котором мы можем указать charset
не используется
в GET запросах.
Но, т.к. в JavaScript есть 2 удобные функции для перевода любой строки в строку с escape-последовательностями в UTF-8, то все их используют, и работают с UTF-8.
Именно поэтому в jQuery даже нельзя никак указать charset при отправке запроса.
Именно поэтому в Prototype.js, даже когда указываешь encoding="windows-1251", и используешь GET запрос, то передается всё равно UTF-8.
Просто потому что в кодах этих библиотек используется функция encodeURIComponent().
Что ж. В этом нет совершенно ничего плохого. Всё, что надо сделать, чтобы теперь работать
в PHP в
нормальной кодировке использовать iconv:
$f = iconv("UTF-8", "windows-1251", $_GET["f"]);
Кстати, мы можем это сделать именно потому, что $_GET работает так, что он понимает
escape-последовательности. Спасибо создателям PHP.
Т.е. когда приходит GET запрос PHP смотрит на URL, создает для нас массив $_GET, а мы
уже с ним
что хотим, то и делаем. Но это вроде понятно должно быть.
2) POST-запросы.
Здесь уже всё интереснее.
Вот приходит это запрос на сервер. Обработчик PHP смотрит на Content-type, и в зависимости от него заполняет массив $_POST и/или переменную $HTTP_RAW_POST_DATA.
$_POST он заполняет в том случае, когда в Content-type указано multipart/form-data или
x-www-form-urlencoded.
Что-же это за Content-type такой?
А контент-тайп это очень удобный. Он позволяет передать php скрипту несколько переменных.
Что по сути такое POST запрос?
Это заголовки, а за ними контент. Контент вообще произвольный. Т.е. просто байты, байты, байты.
Но ведь из JavaScript обычно требуется передать не просто байты, байты, байты, а несколько пар ключ=значение, ключ=значение,…
Как в GET запросе.
Вот люди и договорились о таком удобном типе, как x-www-form-urlencoded
Для того, чтобы передать f=123 и gt=null необходимо передать контент:
Знакомо неправда ли? Конечно знакомо, и тип не зря называется x-www-form-urlencoded.
Всё то же самое, что и при GET запросе.
И как же формируется контент в библиотеках jQuery и prototype.js?
Верно, при помощи всё той же функции encodeURIComponent(), а значит и escape-последовательности будут в кодировке UTF-8. (Независимо от того, что в prototype.js вы установите encoding).
Всё. Осталась ещё одна возможность. Ведь можно передавать не x-www-form-urlencoded (т.е. не параметры), а обычный текстовый или бинарный контент, который потом можно будет прочитать через $HTTP_RAW_POST_DATA.
Для этого устанавливаем Content-type text/xml или application/octet-stream, там же устанавливаем charset=«windows-1251».
Засовываем в функцию send() строку нужной кодировки. (Prototype.js оборачивает этот вызов конструкцией new Ajax.Request(...)).
И что потом… А он (объект класса XMLHttpRequest) переводит эту строку в UTF-8, в какой бы кодировке она не была. Так написано в документации W3C. И он реально это делает.
Выводы:
2. Можно передавать строки как бы «в любых других кодировках», если нелатинские символы
при этом за-escape-ены.
3. В JavaScript существует 3 функции, которые escape-ят нелатинские символы:
escape(), encodeURI() и encodeURIComponent().
Первая переводит в кривой Unicode. Вторые две в UTF-8.
Можно написать свои функции, которые будут генерировать escape-последовательности любой кодировки. Можно, но не нужно. Т.к. наоборот надо радоваться, что есть такие вот функции, которые переводят текст любой кодировки в UTF-8. Это черезвычайно прекрасный факт. Схема при которой все xhtml страницы работают на windows-1251, ajax с сервера клиенту кидает windows-1251, а ajax с клиента серверу кидает UTF-8 абсолютна приемлема и используется на большинстве ресурсов .
Просто не надо забывать использовать iconv как было описано ниже. А для того, чтобы сервер отдавал яваскрипту JSON (или что там у вас) в правильной кодировке (т.е. в такой же кодировке, в которой отдаются все xhtml страницы) просто в начале вашего ajax.php пропишите заголовок:
Header("Content-type: text/html; charset=windows-1251");
И всё будет ок.
На последок немного субъективного мнения:
Используйте jQuery, любите людей, дарите подарки.
Многие разработчики уже не раз сталкивались с множеством проблем с кодировкой в jQuery Ajax и PHP. Давайте разберём причины их возникновения.
Я априори надеюсь, что никто не делает страницу на сервере и клиенте в разных кодировках...
1. Перекодируйте все страницы в utf-8 , так как данная кодировка мультиязычна и с ней у Вас в будущем не возникнет проблем.
2. Если Вы передаёте данные в jQuery Ajax методом GET, возможно у Вас возникла проблема с передачей текста (данных) в кириллице (на русском языке). Почему так? Так как IE, например, передаёт данные не в utf-8. Используем encodeURIComponent
$.ajax({
dataType: "html",
type: "GET",
url: "ajax.php",
data: "query="+encodeURIComponent("Русский текст"),
success: function(data){
alert(data)
}
});
И русский текст передаётся нормально, а, например, не в знаках вопроса.
3. Для справки, правильно писать utf-8 (везде писать так!), а не utf8, windows-1251 , а не windows1251 и тд. Из-за этого тоже могут быть проблемы. Например, в IE, так как он с трепетом относится в правильному написанию. До сих, до сих пор...
В случае с Ajax в PHP частью обработки данных
4. Не забывайте в заголовке прописывать, в какой кодировке Вы хотите принять данные. Пишется в самом начале документа.
// в начале страницы php
header("Content-Type: text/plain; charset=utf-8");
// вручную перекодируем полученные данные
$name = iconv("UTF8","CP1251",$_GET["name"]);
5. Если Вы записываете данные в базу данных, то не забывайте дать понять серверу, в какой кодировке они ему придут/уйдут/откуда так придут/как записать
Mysql_query("SET character_set_results = "utf-8", character_set_client = "utf-8", character_set_connection = "utf-8", character_set_database = "utf-8", character_set_server = "utf-8"", $db);
Если у Вас проблемы, то пишите в комментариях. Разберёмся)
Я выполняю запрос AJAX к скрипту PHP в JavaScript и с помощью библиотеки jQuery.
Вот моя команда, которая выполняет запрос AJAX:
$. ({ async: "false", cache: "false", data: {login: strLogin, password: strPassword}, datatype: "text", error: connexionAjaxError, success: connexionAjaxSuccess, type: "POST", url: "./Connexion" });
«.Connexion» – это перенаправление URL-адресов на мой PHP-скрипт.
connexionAjaxError – это функция JavaScript, которая неизбежно выполняется, как только получен ответ HTTP.
Причина. Мой PHP-скрипт приводит к текстовой / простой странице с кодом состояния HTTP, равным 500.
Вот наиболее важная часть моего PHP-скрипта:
Вот подпись функции callexionAjaxError callback:
Function connexionAjaxError(jqXHR, textStatus, errorThrown)
Мой PHP-результат соответствует строке «été».
Внутренняя кодировка PHP – это ISO-8859-1, поэтому строка результата кодируется в шестнадцатеричной системе.
Но jqXHR.responseText в функции callexionAjaxError вызывает 1-символьную строку.
Я использовал метод charCodeAt объекта JavaScript String для получения кода юникода (UTF-8?) Для символа.
Символ кодируется 65535 в десятичной нотации, эквивалентной в шестнадцатеричной нотации.
Я не понимаю, почему jqXHR.responseText не содержит 3-символьную строку «été».
Я не эксперт в JavaScript, но я полагаю, что jqXHR.responseText может содержать только строку, закодированную в UTF-8.
Таким образом, строка «été» в jqXHR.responseText будет закодирована в шестнадцатеричной нотации.
Я получил код UTF-8 для символа «é» со следующего веб-сайта: http://www.utf8-chartable.de/
Я делаю много развития на испанском языке, и я заметил несколько вещей, которые могут вам помочь, поскольку я уже прошел через это:
Кодировка в функции заголовка должна быть UTF-8.
Кроме того, сам FILE (скрипт PHP) должен быть сохранен в UTF-8, вы можете легко достичь этого, если вы отредактируете файл с помощью Notepad ++ и выберите кодировку UTF-8 без спецификации.
То же самое касается ваших javascript и HTML-файлов, все они должны быть закодированы с помощью UTF-8 без спецификации, а не ANSI.
Дай мне знать!
Попробуйте установить Contenttype, как это в вашем вызове, насколько я знаю jQuery Ajax всегда utf-8, если не указано.
$.ajax({ ... datatype: "text", contentType: "application/x-www-form-urlencoded;charset=ISO-8859-1", error: connexionAjaxError, success: connexionAjaxSuccess, type: "POST", ... });
Изменить: если мой ответ не поможет, это может помочь, если вы проверите конфигурацию набора символов сервера, а также разместите его.