Конфигурирование Tomcat 5.5 для UTF-8 кодирует все перенаправления sendRedirect ()? - PullRequest
2 голосов
/ 11 мая 2009

Требуемым продуктом, который мы создаем, является то, что его конечные точки URL семантически значимы для пользователей на их родном языке. Это означает, что нам нужны URL в кодировке UTF-8 для поддержки каждого алфавита под солнцем.

Мы также не хотели бы предоставлять документацию конфигурации установки для каждого сервера приложений и версии, которые мы поддерживаем, поэтому было бы неплохо, если бы мы могли выполнить это в коде. Это может быть невозможно, поскольку к тому времени, когда сервлет получил запрос, он был закодирован сервером приложений и т. Д.

Я получил эту работу (для моего первого варианта использования с использованием символов ASCII, не входящих в США, в латинском языке ISO), воссоздав информацию о пути запроса с помощью:

String pathInfoEncoded = new String(httpServletRequest.getPathInfo().getBytes(), "UTF-8");

и затем анализируем это.

Однако, это не работает после перенаправления из POST в GET с помощью sendRedirect (). Путь запроса приходит уже экранированным (поэтому ö кодируется как% F6), и мой метод, описанный выше, не работает.

Так что я думаю, что мой вопрос, я все об этом говорю неправильно? И если так, что является противоядием от моего невежества? :)

Обновление: найдено решение. Проблема в том, что Servlet API имеет странное поведение в отношении кодировки URL перед отправкой перенаправления. Вы должны кодировать URL (экранировать символы UTF-8) ДО того, как вызовете sendRedirect (). Метод encodeRedirectURL () не делает этого за вас.

На этой странице обсуждается это: http://www.whirlycott.com/phil/2005/05/11/building-j2ee-web-applications-with-utf-8-support/

Ответы [ 3 ]

4 голосов
/ 11 мая 2009

Пара вещей для исследования и экспериментов:

  • Взгляните на ваш файл ./conf/server.xml и убедитесь, что для соединителя атрибут URIEncoding установлен на "UTF-8".

например:.

<Connector port="8080" 
           protocol="HTTP/1.1" 
           URIEncoding="UTF-8"/>
  • Воспользуйтесь каким-нибудь браузерным инструментом (например, TamperData для FireFox), чтобы увидеть, что ваш браузер отправляет на сервер - он вполне может его избежать. В этом случае вы можете использовать URL.decode () на сервере.
  • Вместо использования Response.redirect (), вручную установите заголовки и код ответа.

например:.

response.setHeader("Location", myUtf8unencodedUrl);
response.setStatus(response.SC_MOVED_TEMPORARILY);

Никаких обещаний, но это то, что я бы попробовал, если бы это был я. :)

2 голосов
/ 12 мая 2009

нашел решение. Проблема в том, что Servlet API имеет странное поведение в отношении кодировки URL перед отправкой перенаправления. Вы должны кодировать URL (экранировать символы UTF-8) ДО того, как вызовете sendRedirect (). Метод encodeRedirectURL () не делает этого за вас.

Эта страница обсуждает это: http://www.whirlycott.com/phil/2005/05/11/building-j2ee-web-applications-with-utf-8-support/

1 голос
/ 17 сентября 2009

У нас такая же ситуация, т. Е. Наш продукт также должен показывать значимые URL-адреса пользователю практически на всех языках мира. Все наши инструменты и технологии поддерживают UTF-8, поэтому никаких проблем с этим нет. Технически работает экранирование символов UTF-8, но IE (7, 8) отображает отвратительно выглядящие экранированные URL-адреса, тогда как Firefox снимает их с экранирования и отображает красивые URL-адреса, т. Е. «/Français/Banane.html» будет отображаться в IE как «/ fran%» C3% A7ais / Banane.html». GET после POST / перенаправления после отправки формы вообще не работал, ни отправка URL-адресов UTF-8, ни экранирование URL-адресов UTF-8. Мы также безуспешно пытались использовать числовое кодирование сущностей в стиле XML.

Однако мы наконец нашли способ успешно перенаправить после POST: кодировать строку UTF-8 байтово, используя ISO-8859-1. Никто из нас действительно не понимает, как это может работать в любом случае (как браузер может знать, как его декодировать, так как число байтов на символ utf-8 может изменяться и как браузер узнает, что изначально это был utf-8?), Но это делает.

Вот простой сервлет, чтобы попробовать это:


package springapp.web.servlet;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;

public class TestServlet extends HttpServlet {

 private static final long serialVersionUID = -1743198460341004958L;

 /* (non-Javadoc)
  * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
  */
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {

  String url = "çöffte.html"; 
  try {
         ServletContext context = req.getSession().getServletContext();
   // read utf8 encoded russian url
            if (context.getResource("/WEB-INF/ru_url.txt") != null){
             InputStream is = context.getResourceAsStream("/WEB-INF/ru_url.txt"); 
             if (is != null){
              url = IOUtils.toString(is, "UTF-8");
              System.out.println(String.format("Redirecting to [%s]", url));
             }
            }
        }
        catch (FileNotFoundException fNFEx) {
         fNFEx.printStackTrace();
        }
        catch (IOException ioEx) {
         ioEx.printStackTrace();
        }

        byte[] utfBytes = url.getBytes("UTF-8");
        String result = new String(utfBytes, "ISO-8859-1");
        resp.sendRedirect(result);

        // does not work:
        //resp.sendRedirect(url);
        //resp.sendRedirect(Utf8UrlEscaper.escapeUtf8(url));
        //resp.sendRedirect(Utf8UrlEscaper.escapeToNumericEntity(url));
 }
}

Для перенаправления целевой копии скопируйте и вставьте URL любого родного языка, например, из википедии в файл с кодировкой utf-8 (без спецификации!) и сохраните его в каталоге WEB-INF. В нашем примере мы взяли русский URL (http://ru.wikipedia.org/wiki/Заглавная_страница) и сохраните его в файле с именем 'ru_url.txt'.

Мы создали простое приложение SpringMVC, отображающее любой * .abc URL в тестовый сервлет. Теперь, если вы запустите приложение и введете что-то вроде 'localhost: 8080 / springmvctest / a.abc', вы будете перенаправлены на сайт русской википедии, а браузер (IE и Firefox, Safari или, возможно, нет) должен показать хороший utf- 8 закодированный, родной russion url.

...