4 мая 2010 г.

Хитрости Apache Tomcat: Кодировка

При разработке сервлетов, которые на основе запроса от HTML или JSP-страницы генерируют другую страницу, можно натолкнуться на некоторые трудности с кодировкой данных, отправляемых на сервер (request) и получаемых от него (response).

Для определения кодировки данных ответа необходимо использовать метод setCharacterEncoding объекта класса HttpServletResponse. Например, для установки UTF-8:
public class FooServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException {
        
        response.setCharacterEncoding("UTF-8");
        
        // далее остальной код...
    }
 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException {
        doPost (request, response);
    }
}
А вот с кодировкой данных, которые будут отправлены в запросе на сервер есть небольшая хитрость. Казалось бы, если страница сформирована, допустим, в кодировке UTF-8, то и данные запроса должны обрабатываться сервером, как UTF-8. Однако, этого не происходит, потому что в запросе браузер не передает информацию о кодировке данных. Если для отправки данных формы используется метод POST, то все просто - можно точно так же вызвать метод setCharacterEncoding, только для объекта класса HttpServletRequest:
request.setCharacterEncoding("UTF-8");
Проблема возникнет, если для отправки данных формы будет использоваться метод GET. В таком случае request.setCharacterEncoding("UTF-8") уже не сработает и Tomcat будет обрабатывать строку запроса так, как-будто она в кодировке ISO8859-1.

Для решения этой проблемы необходимо подправить конфигурационный файл Apache Tomcat server.xml и в тег Connector добавить параметр useBodyEncodingForURI="true":
<Connector connectionTimeout="20000" 
      port="8081" protocol="HTTP/1.1" 
      redirectPort="8443" useBodyEncodingForURI="true"/>
После этого перезагружаем Tomcat и для метода GET можно будет также использовать request.setCharacterEncoding("UTF-8") для указания кодировки запроса:
public class FooServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException {
        
        response.setCharacterEncoding("UTF-8"); // кодировка ответа
        request.setCharacterEncoding("UTF-8");  // кодировка запроса; необходимо указать до
                                                // вызова request.getParameter()
        
        // далее остальной код...
        String param1=request.getParameter("param1");  
        String param2=request.getParameter("param2");
      
        // ...
    }
 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException {
        doPost (request, response);
    }
}
В том же теге Connector, используя параметр URIEncoding вместо useBodyEncodingForURI, можно явно установить нужную для вас кодировку, например URIEncoding="UTF-8", решайте сами, что для вас удобнее.

12 комментариев:

  1. спасибо за комплексное решение проблемы))))

    правда я думаю стоить добавить тот момент, что в проекте по умолчаниях в настройке "Project properties/Resource/Text File encoding" используется кодировка "win-1251" и у меня не работало до тех пор, пока я не изменил этот параметр на UTF8. После этой операции конечно пришлось переписать все слова наново, но зато заработало!!!

    еще раз спасибо!!!

    ОтветитьУдалить
  2. Рад что помогло!

    Ваше замечание, на сколько я понимаю, справедливо только если вы работаете под Windows, и если вы в самом коде пишите значения параметров русскими буквами, т.е. когда они берутся не из формы. win-1251 родная кодировка для винды, поэтому и файлы с исходным кодом в эклипсе по умолчанию в этой кодировке. У меня Linux, поэтому я как-то даже и не задумался о такой ситуации.

    Если вы программируете для вэб, то всегда и везде используйте UTF-8, и не будет проблем :)

    ОтветитьУдалить
  3. Чувак, спасибо тебе огромное!

    ОтветитьУдалить
  4. спасибо, пригодилось...

    ОтветитьУдалить
  5. Целый день бился над проблемой кодировки в своём сервлете. После того как подправил server.xml тоже была неправильная кодировка. Оказалось это мой косяк. Надо было поменять местами строки в doGet():
    PrintWriter out = response.getWriter();
    response.setContentType("text/html;charset=Windows-1251");

    Спасибо

    ОтветитьУдалить
  6. Спасибо огромное! Пост очень полезен!

    ОтветитьУдалить
  7. Спасибо большое! Решила проблему!

    ОтветитьУдалить
  8. Спасибо! Статья очень помогла. Проблема решилась только двумя строчками
    response.setContentType("text/html; charset=UTF-8"); и request.setCharacterEncoding("UTF-8");
    и даже ничего не пришлось менять/добавлять в файле server.xml.

    ОтветитьУдалить