HTTP кодирование / декодирование заголовков в Java - PullRequest
13 голосов
/ 27 ноября 2008

Пользовательский заголовок HTTP передается в приложение сервлета для аутентификации. Значение заголовка должно содержать акценты и другие символы, не входящие в ASCII, поэтому оно должно быть в определенной кодировке (в идеале UTF-8).

Разработчики, управляющие средой аутентификации, предоставляют этот фрагмент кода Java:

String firstName = request.getHeader("my-custom-header"); 
String decodedFirstName = new String(firstName.getBytes(),"UTF-8");

Но этот код мне не подходит: он предполагает кодирование значения заголовка, когда мне показалось, что существует правильный способ указать кодировку для значений заголовка (я полагаю, из MIME).

Вот мой вопрос: как правильно (tm) работать с пользовательскими значениями заголовка, которые должны поддерживать кодировку UTF-8:

  • на проводе (как заголовок выглядит на проводе)
  • с точки зрения декодирования (как декодировать его с помощью Java Servlet API, и можем ли мы предположить, что request.getHeader () уже правильно выполняет декодирование)

Вот пример кода, независимого от среды, для обработки заголовков как UTF-8 в случае, если вы не можете изменить свой сервис:

String valueAsISO = request.getHeader("my-custom-header"); 
String valueAsUTF8 = new String(firstName.getBytes("ISO8859-1"),"UTF-8");

Ответы [ 5 ]

7 голосов
/ 31 декабря 2008

Опять же: RFC 2047 не реализован на практике. Следующая версия HTTP / 1.1 удалит все упоминания о ней.

Итак, если вам нужно транспортировать символы, не входящие в ASCII, самый безопасный способ - это закодировать их в последовательность ASCII, такую ​​как заголовок «Slug» в протоколе публикации Atom.

5 голосов
/ 31 декабря 2008

Рабочая группа HTTPbis знает об этой проблеме, и последние проекты избавляются от всех языков, связанных с кодировкой TEXT и RFC 2047 - на практике она не используется через HTTP.

См. http://trac.tools.ietf.org/wg/httpbis/trac/ticket/74 для всей истории.

4 голосов
/ 27 ноября 2008

Как уже упоминалось, первый взгляд всегда должен идти на HTTP 1.1 spec (RFC 2616). В нем говорится , что текст в значениях заголовка должен использовать кодировку MIME, как определено RFC 2047 , если он содержит символы из наборов символов, отличных от ISO-8859-1.

Так что вот вам плюс. Если ваши требования охватываются кодировкой ISO-8859-1, вы просто помещаете свои символы в свои сообщения запроса / ответа. В противном случае MIME-кодирование является единственной альтернативой.

Пока пользовательский агент отправляет значения в ваши пользовательские заголовки в соответствии с этими правилами, вам не придется беспокоиться о их расшифровке. Вот что должен делать Servlet API.


Однако есть более простая причина, по которой ваш фрагмент кода не делает то, что должен. Первая строка выбирает значение заголовка в виде строки Java. Как мы знаем, он представлен как UTF8 внутри, поэтому на данный момент разбор сообщения HTTP-запроса уже завершен и завершен.

Следующая строка выбирает байтовый массив этой строки. Поскольку кодировка не указана (ИМХО этот метод без аргументов давно должен был быть признан устаревшим), используется текущая кодировка системы по умолчанию, которая обычно не является UTF8, а затем массив снова преобразуется в кодировку UTF8. Outch.

4 голосов
/ 27 ноября 2008

См. HTTP-спецификацию для правил, которые описаны в разделе 2.2

Правило TEXT используется только для содержимого описательных полей и значений, которые не предназначены для интерпретации анализатором сообщений. Слова * TEXT МОГУТ содержать символы из наборов символов, отличных от ISO-8859-1 [22], только если они закодированы в соответствии с правилами RFC 2047 [14].

Приведенный выше код не будет правильно декодировать строку кодирования RFC2047, из-за чего я полагаю, что служба не соответствует спецификации, а просто встраивает необработанные данные utf-8 в заголовок.

3 голосов
/ 01 декабря 2008

Спасибо за ответы. Кажется, что идеальным было бы следовать правильной кодировке HTTP-заголовка согласно RFC 2047. Значения заголовка в UTF-8 на проводе будут выглядеть примерно так:

=?UTF-8?Q?...?=

Теперь вот забавная вещь: кажется, что ни Tomcat 5.5, ни 6 должным образом не декодируют заголовки HTTP согласно RFC 2047! Код Tomcat везде предполагает, что значения заголовков используют ISO-8859-1.

Так что для Tomcat, в частности, я буду работать над этим, написав фильтр, который обрабатывает правильное декодирование значений заголовка.

...