|
втор:
http://mihazimin.blogspot.com
AJAX, — это технология. Одной
из часто используемых техник этой технологии является посылка запросов при
помощи объекта класса XMLHttpRequest.
Классов то, конечно, в JavaScript нет, но для удобства
будем пользоваться такой терминологией.
В документации на XMLHttpRequest сказано, что браузер
должен поддерживать следующие типы HTTP-запросов:
GET, POST, HEAD, PUT,
DELETE, OPTIONS
На сегодняшний день джаваскриптом через объект класса
XMLHttpRequest можно отправить только запросы
типа GET и POST.
Итак, рассмотрим 2 этих запроса:
1) Запрос типа GET:
Вся информация скрипту на сервере может передаваться только
через URL и через заголовки.
Например,
GET http://moy-rebenok/ajax.php?f=324
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
Host: ...
или так:
GET
http://moy-rebenok/ajax.php?f=%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82
Host: ...
Никто вас в этом не ограничивает.
Кстати, для GET запроса не нужно указывать заголовок
Content-Type.
Т.к. никакого контента нет. Есть только запрос по определенному адресу.
Все переменные на сервер передаются через URL.
Как же смастерить необходимую escape последовательность в нужной кодировке?
Мастерить можно хоть руками, хоть как, но естественно в JavaScript.
Опять же, никто вас не ограничивает.
Но для удобства обычно используют одну из 3 функций,
которые уже определены в JavaScript:
а) escape()
б) encodeURI()
в) encodeURIComponent()
По порядку:
а) escape()
Латинские буквы, цифры, символы @*/+. оставляет как есть,
всё остальное кодирует так:
%xx, либо так: %uxxxx.
Причем, xxxx во втором случае, — это код символа не в
UTF-8, а в Unicode
(Разница
между Unicode и
UTF-8).
Использовать эту функцию не надо, т.к. результат
выполнения зависит от браузера, функция не является стандартизированной W3C,
возникла в лихие 90-е.
К тому же, как-то нормально (по крайней мере, быстро)
обработать строку в таком винигретчатом формате на сервере сложно.
Функцию escape() использует библиотека нашего
соотечественника JsHttpRequest.
Не потому что библиотека плохая, а потому что создана для работы со всеми
браузерами
(в том числе и с самыми древними).
б) encodeURI()
Латинские буквы, цифры, символы !@#$&*()=:/;?+'. оставляет
как есть, всё остальное
кодирует
escape-последовательностями в кодировке UTF-8.
Одобрено 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 необходимо
передать контент:
f=123>=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. И он реально это делает.
Выводы:
1. Напрямую через XMLHttpRequest можно передавать только
строки в кодировке UTF-8.
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');
И всё будет ок.
На последок немного субъективного мнения:
|