кодирование русских букв в url
Кодировки и веб-страницы
Возвращаясь к избитой проблеме с кодировками русских букв, хотелось бы иметь под рукой некий единый справочник или руководство, в котором можно найти решения различных сходных ситуаций. В своё время сам перелопатил множество статей и публикаций, чтобы находить причины ошибок. Задача этой публикации — сэкономить время и нервы читателя и собрать воедино различные причины ошибок с кодировками в разработке на Java и JSP и способы их устранения.
Варианты решения могут быть не единственными, охотно добавлю предложенные читателем, если они будут рабочими.
Итак, поехали.
1. Проблема: при получении разработанной мной страницы браузером весь русский текст идёт краказябрами, даже тот, который забит статически.
Причина: браузер неверно определяет кодировку текста, потому что нет явного указания.
Решение: явно указать кодировку:
a) HTML: добавляем тэг META в хидер страницы:
б) XML: указываем кодировку в заголовке:
в) JSP — задаём тип контента в заголовке:
г) JSP — задаём кодировку возвращаемой страницы
д) Java — устанавливаем хидер ответа:
2. Проблема: написанный в JSP-странице статический русский текст почему-то идёт краказабрами, хотя кодировка страницы задана.
Причина: статический текст был написан в кодировке, отличной от заданного странице.
Решение: изменить кодировку в редакторе (например, для AkelPad нажимаем «Сохранить как» и выбираем нужную кодировку).
3. Проблема: получаемый из запроса текст идёт кракозябрами.
Причина: кодировка запроса отличается от используемой для его обработки кодировки.
Решение: установить кодировку запроса или перекодировать в нужную.
а) Java, со стороны отправителя не задана нужная кодировка — перекодируем в нужную:
Примечание: кодировка ISO-8859-1 устанавливается по умолчанию, если не была задана другая.
б) Java, со стороны отправителя задана нужная кодировка — устанавливаем кодировку запроса:
4. Проблема: отправленный GET-параметром русский текст при редиректе приходит кракозябрами.
Причина: упаковка русского текста в URI по умолчанию идёт в ISO-8859-1.
Решение: упаковать текст в нужной кодировке вручную.
а) JSP, URLEncoder:
5. Проблема: текст из базы данных читается кракозябрами.
Причина: кодировка текста, прочитанного из базы данных, отличается от кодировки страницы.
Решение: установить соответствующую кодировку страницы, либо перекодировать полученные из базы данных значения.
а) Java, перекодирование считанной в db_string базы данных строки:
6. Проблема: текст записывается в базу данных кракозябрами, хотя на странице отображается правильно.
Причина: кодировка записываемой строки отличается от кодировки сессии работы с базой данных, либо от кодировки базы данных (стоит помнить, что они не всегда совпадают).
Решение: установить необходимую кодировку сессии или перекодировать строку.
а) Java, перекодирование записываемой строки db_string в кодировку сессии или базы данных:
б) Java, MySQL, настройка параметров подключения в строке dburl, передаваемой функции коннекта:
в) MySQL, настройка параметров подключения в XML-описателе контекста, добавляем атрибут к тегу \ :
г) MySQL, прямая установка кодировки сессии вызовом SET NAMES (connect — объект подключения Connection):
7. Проблема: если ничего не помогло…
Решение: всегда остаётся самый «топорный» метод — прямое перекодирование.
а) Для известной кодировки источника:
[String MyValue = new String(source_string.getBytes(«utf-8″),»cp1251»);]
б) Для параметра запроса:
[String MyValue = new String(request.getParameter(«MyParam»).getBytes(request.getCharacterEncoding()),»cp1251″);]
Дополнение, или что нужно знать:
1. Кодировки базы данных и сессии подключения могут различаться, в зависимости от конкретной СУБД и драйвера. К примеру, при подключении к MySQL стандартным драйвером com.mysql.jdbc.Driver без явного указания кодировка сессии устанавливалась в UTF-8, несмотря на другую кодировку схемы БД.
2. Кодировка упаковки строки запроса в URI по умолчанию устанавливается в ISO-8859-1. С подобным можно столкнуться, например, при передаче явно заданного текста в редиректе с одной страницы на другую.
3. Взаимоотношения кодировок страницы, базы данных, сессии, параметров запроса и ответа не зависят от языка разработки и описанные для Java функции имеют аналоги для PHP, Asp и других.
Примечание: восстановить ссылки на источники нет возможности, все примеры взяты из собственного кода, хотя когда-то так же выискивал их по многочисленным форумам.
Надеюсь, этот небольшой обзор поможет начинающим веб-программистам сократить время отладки и сберечь нервы.
Разберемся раз и навсегда: AJAX, «кириллические символы», кодировки, prototype.js, jQuery, JsHttpRequest
AJAX, — это технология. Одной из часто используемых техник этой технологии является
посылка запросов при помощи объекта класса XMLHttpRequest.
Как же посылать и принимать AJAX запросы в нужной нам кодировке, нужно ли использовать однобайтовые кодировки или не обойтись без UTF-8. На все эти вопросы раз и навсегда ответит эта статья.
Кстати, перепечатка с моего.
И ещё, классов-то, конечно, в JavaScript нет, но для удобства будем пользоваться такой терминологией.
В документации на XMLHttpRequest сказано, что браузер должен поддерживать следующие типы
HTTP-запросов: GET, POST, HEAD, PUT, DELETE, OPTIONS.
На сегодняшний день джаваскриптом через объект класса XMLHttpRequest можно отправить
только запросы типа GET и POST.
Итак, рассмотрим 2 этих запроса:
Вся информация скрипту на сервере может передаваться только через URL и через заголовки.
GET 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: 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 запроса не нужно указывать заголовок Content-Type.
Т.к. никакого контента нет. Есть только запрос по определенному адресу.
Все переменные на сервер передаются через URL.
Как же смастерить необходимую escape последовательность в нужной кодировке?
Мастерить можно хоть руками, хоть как, но естественно в JavaScript.
Опять же, никто вас не ограничивает.
Но для удобства обычно используют одну из 3 функций, которые уже определены в JavaScript:
а) escape()
б) encodeURI()
в) encodeURIComponent()
Латинские буквы, цифры, символы @*/+. оставляет как есть, всё остальное кодирует так:
%xx, либо так: %uxxxx.
Причем, xxxx во втором случае, — это код символа не в UTF-8, а в Unicode
Использовать эту функцию не надо, т.к. результат выполнения зависит от браузера, функция не является стандартизированной W3C, возникла в лихие 90-е.
К тому же, как-то нормально (по крайней мере, быстро) обработать строку в таком винигретчатом формате на сервере сложно.
Функцию escape() использует библиотека нашего соотечественника JsHttpRequest.
Не потому что библиотека плохая, а потому что создана для работы со всеми браузерами
(в том числе и с самыми древними).
Используется 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:
Здесь уже всё интереснее.
$_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).
Для этого устанавливаем 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’);
На последок немного субъективного мнения:
Используйте jQuery, любите людей, дарите подарки.
HTML Кодирование URL адресов. Справочник
Курс по основам HTML. W3Schools на русском. Уроки для начинающих
Кодирование URL преобразует символы в формат, который может быть передан через Интернет.
Веб-браузеры запрашивают страницы с веб-серверов с помощью URL-адреса.
Кодирование URL (кодирование с процентами)
URL-адреса можно отправлять только через Интернет с помощью набора символов ASCII.
Поскольку URL-адреса часто содержат символы вне набора ASCII, URL-адрес должен быть преобразован в правильный формат ASCII.
Кодирование URL заменяет опасные символы ASCII на «%», за которыми следуют две шестнадцятеричные цифры.
URL-адреса не могут содержать пробелы. Кодирование URL обычно заменяет пробел знаком плюс (+) или %20.
Попробуйте сами
Если нажать кнопку Submit («Отправить») ниже, браузер закодирует входной URL-адрес прежде, чем он будет отправлен на сервер. Страница на сервере отобразит полученные данные.
Попробуйте ввести другие данные и опять нажмите Submit («Отправить») (работает только на странице сайта https://www.w3schools.com/).
Функции кодирования URL-адресов
В JavaScript, PHP и ASP существуют функции, которые можно использовать для URL-кодирования строки.
PHP имеет функцию rawurlencode(), а ASP имеет функцию Server.URLEncode().
В JavaScript можно использовать функцию encodeURIComponent().
Нажмите кнопку «URL Encode», чтобы увидеть, как функция JavaScript кодирует текст (работает только на сайте w3schools.com).
Примечание: Функция JavaScript кодирует пробел как %20.
ASCII Кодировки. Справочник
Ваш браузер будет кодировать входящие данные в соответствие набору символов, который используется на веб-странице.
| Символ | Из Windows-1252 | Из UTF-8 |
|---|---|---|
| space | %20 | %20 |
| ! | %21 | %21 |
| « | %22 | %22 |
| # | %23 | %23 |
| $ | %24 | %24 |
| % | %25 | %25 |
| & | %26 | %26 |
| ‘ | %27 | %27 |
| ( | %28 | %28 |
| ) | %29 | %29 |
| * | %2A | %2A |
| + | %2B | %2B |
| , | %2C | %2C |
| — | %2D | %2D |
| . | %2E | %2E |
| / | %2F | %2F |
| 0 | %30 | %30 |
| 1 | %31 | %31 |
| 2 | %32 | %32 |
| 3 | %33 | %33 |
| 4 | %34 | %34 |
| 5 | %35 | %35 |
| 6 | %36 | %36 |
| 7 | %37 | %37 |
| 8 | %38 | %38 |
| 9 | %39 | %39 |
| : | %3A | %3A |
| ; | %3B | %3B |
| %3E | %3E | |
| ? | %3F | %3F |
| @ | %40 | %40 |
| A | %41 | %41 |
| B | %42 | %42 |
| C | %43 | %43 |
| D | %44 | %44 |
| E | %45 | %45 |
| F | %46 | %46 |
| G | %47 | %47 |
| H | %48 | %48 |
| I | %49 | %49 |
| J | %4A | %4A |
| K | %4B | %4B |
| L | %4C | %4C |
| M | %4D | %4D |
| N | %4E | %4E |
| O | %4F | %4F |
| P | %50 | %50 |
| Q | %51 | %51 |
| R | %52 | %52 |
| S | %53 | %53 |
| T | %54 | %54 |
| U | %55 | %55 |
| V | %56 | %56 |
| W | %57 | %57 |
| X | %58 | %58 |
| Y | %59 | %59 |
| Z | %5A | %5A |
| [ | %5B | %5B |
| \ | %5C | %5C |
| ] | %5D | %5D |
| ^ | %5E | %5E |
| _ | %5F | %5F |
| ` | %60 | %60 |
| a | %61 | %61 |
| b | %62 | %62 |
| c | %63 | %63 |
| d | %64 | %64 |
| e | %65 | %65 |
| f | %66 | %66 |
| g | %67 | %67 |
| h | %68 | %68 |
| i | %69 | %69 |
| j | %6A | %6A |
| k | %6B | %6B |
| l | %6C | %6C |
| m | %6D | %6D |
| n | %6E | %6E |
| o | %6F | %6F |
| p | %70 | %70 |
| q | %71 | %71 |
| r | %72 | %72 |
| s | %73 | %73 |
| t | %74 | %74 |
| u | %75 | %75 |
| v | %76 | %76 |
| w | %77 | %77 |
| x | %78 | %78 |
| y | %79 | %79 |
| z | %7A | %7A |
| < | %7B | %7B |
| | | %7C | %7C |
| > | %7D | %7D |
| %7E | %7E | |
| %7F | %7F | |
| ` | %80 | %E2%82%AC |
| | %81 | %81 |
| ‚ | %82 | %E2%80%9A |
| ƒ | %83 | %C6%92 |
| „ | %84 | %E2%80%9E |
| … | %85 | %E2%80%A6 |
| † | %86 | %E2%80%A0 |
| ‡ | %87 | %E2%80%A1 |
| ˆ | %88 | %CB%86 |
| ‰ | %89 | %E2%80%B0 |
| Š | %8A | %C5%A0 |
| ‹ | %8B | %E2%80%B9 |
| Œ | %8C | %C5%92 |
| | %8D | %C5%8D |
| Ž | %8E | %C5%BD |
| | %8F | %8F |
| | %90 | %C2%90 |
| ‘ | %91 | %E2%80%98 |
| ’ | %92 | %E2%80%99 |
| “ | %93 | %E2%80%9C |
| ” | %94 | %E2%80%9D |
| • | %95 | %E2%80%A2 |
| – | %96 | %E2%80%93 |
| — | %97 | %E2%80%94 |
| ˜ | %98 | %CB%9C |
| ™ | %99 | %E2%84 |
| š | %9A | %C5%A1 |
| › | %9B | %E2%80 |
| œ | %9C | %C5%93 |
| | %9D | %9D |
| ž | %9E | %C5%BE |
| Ÿ | %9F | %C5%B8 |
| %A0 | %C2%A0 | |
| ¡ | %A1 | %C2%A1 |
| ¢ | %A2 | %C2%A2 |
| £ | %A3 | %C2%A3 |
| ¤ | %A4 | %C2%A4 |
| ¥ | %A5 | %C2%A5 |
| ¦ | %A6 | %C2%A6 |
| § | %A7 | %C2%A7 |
| ¨ | %A8 | %C2%A8 |
| © | %A9 | %C2%A9 |
| ª | %AA | %C2%AA |
| « | %AB | %C2%AB |
| ¬ | %AC | %C2%AC |
| | %AD | %C2%AD |
| ® | %AE | %C2%AE |
| ¯ | %AF | %C2%AF |
| ° | %B0 | %C2%B0 |
| ± | %B1 | %C2%B1 |
| ² | %B2 | %C2%B2 |
| ³ | %B3 | %C2%B3 |
| ´ | %B4 | %C2%B4 |
| µ | %B5 | %C2%B5 |
| ¶ | %B6 | %C2%B6 |
| · | %B7 | %C2%B7 |
| ¸ | %B8 | %C2%B8 |
| ¹ | %B9 | %C2%B9 |
| º | %BA | %C2%BA |
| » | %BB | %C2%BB |
| ¼ | %BC | %C2%BC |
| ½ | %BD | %C2%BD |
| ¾ | %BE | %C2%BE |
| ¿ | %BF | %C2%BF |
| À | %C0 | %C3%80 |
| Á | %C1 | %C3%81 |
| Â | %C2 | %C3%82 |
| Ã | %C3 | %C3%83 |
| Ä | %C4 | %C3%84 |
| Å | %C5 | %C3%85 |
| Æ | %C6 | %C3%86 |
| Ç | %C7 | %C3%87 |
| È | %C8 | %C3%88 |
| É | %C9 | %C3%89 |
| Ê | %CA | %C3%8A |
| Ë | %CB | %C3%8B |
| Ì | %CC | %C3%8C |
| Í | %CD | %C3%8D |
| Î | %CE | %C3%8E |
| Ï | %CF | %C3%8F |
| Ð | %D0 | %C3%90 |
| Ñ | %D1 | %C3%91 |
| Ò | %D2 | %C3%92 |
| Ó | %D3 | %C3%93 |
| Ô | %D4 | %C3%94 |
| Õ | %D5 | %C3%95 |
| Ö | %D6 | %C3%96 |
| × | %D7 | %C3%97 |
| Ø | %D8 | %C3%98 |
| Ù | %D9 | %C3%99 |
| Ú | %DA | %C3%9A |
| Û | %DB | %C3%9B |
| Ü | %DC | %C3%9C |
| Ý | %DD | %C3%9D |
| Þ | %DE | %C3%9E |
| ß | %DF | %C3%9F |
| à | %E0 | %C3%A0 |
| á | %E1 | %C3%A1 |
| â | %E2 | %C3%A2 |
| ã | %E3 | %C3%A3 |
| ä | %E4 | %C3%A4 |
| å | %E5 | %C3%A5 |
| æ | %E6 | %C3%A6 |
| ç | %E7 | %C3%A7 |
| è | %E8 | %C3%A8 |
| é | %E9 | %C3%A9 |
| ê | %EA | %C3%AA |
| ë | %EB | %C3%AB |
| ì | %EC | %C3%AC |
| í | %ED | %C3%AD |
| î | %EE | %C3%AE |
| ï | %EF | %C3%AF |
| ð | %F0 | %C3%B0 |
| ñ | %F1 | %C3%B1 |
| ò | %F2 | %C3%B2 |
| ó | %F3 | %C3%B3 |
| ô | %F4 | %C3%B4 |
| õ | %F5 | %C3%B5 |
| ö | %F6 | %C3%B6 |
| ÷ | %F7 | %C3%B7 |
| ø | %F8 | %C3%B8 |
| ù | %F9 | %C3%B9 |
| ú | %FA | %C3%BA |
| û | %FB | %C3%BB |
| ü | %FC | %C3%BC |
| ý | %FD | %C3%BD |
| þ | %FE | %C3%BE |
| ÿ | %FF | %C3%BF |
Справочник URL кодировок
Набор символов ASCII %00-%1F сначала разрабатывался для управления аппаратными устройствами.
Наборы символов не имеют никакого отношения к URL-адресам.