Статьи

Правильное декодирование параметров URL на стороне сервера в JBoss

Сегодня я потратил много часов, чтобы понять, как заставить правильно декодировать закодированные символы в приложениях JSF, работающих на JBoss (используя JBoss 7 Final). Проблема возникает, когда у вас есть, например, китайские символы, переданные через URL. Предположим, у вас есть 指 事, закодированный как% E6% 8C% 87% E4% BA% 8B. Удивительно, но эти персонажи попадают на серверную сторону как æŒ ‡ äº ‹. Они декодируются сервером автоматически с ISO-8859-1. Таким образом, не имеет значения, если вы попытаетесь расшифровать его самостоятельно, например:

1
2
3
FacesContext fc = FacesContext.getCurrentInstance();
String param = fc.getExternalContext().getRequestParameterMap().get(name);
String decodedParam = java.net.URLDecoder.decode(param, "UTF-8");

Это не помогает, потому что символы уже были неправильно декодированы, а вы уже неправильно их декодировали из карты параметров запроса. Это тоже не поможет, если у вас есть на странице

1
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>

Чтобы преодолеть эту ошибку, вам нужны две вещи: специальный фильтр кодировки символов и конфигурация в standalone.xml JBoss. Фильтр должен установить настроенную кодировку для запроса и ответа.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class CharacterEncodingFilter implements Filter {
 
    /** The default character encoding to set for request / response. */
    private String encoding = null;
 
    /** The filter configuration object. */
    private FilterConfig filterConfig;
 
    /** Should a character encoding specified by the client be ignored? */
    private boolean ignore = true;
 
    public void destroy() {
        encoding = null;
        filterConfig = null;
    }
 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
        ServletException {
        // conditionally select and set the character encoding to be used
        if ((ignore || (request.getCharacterEncoding() == null)) && (encoding != null)) {
            request.setCharacterEncoding(encoding);
            response.setCharacterEncoding(encoding);
        }
 
        // pass control on to the next filter
        chain.doFilter(request, response);
    }
 
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
        this.encoding = filterConfig.getInitParameter("encoding");
 
        String value = filterConfig.getInitParameter("ignore");
 
        this.ignore = ((value == null) || value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes"));
    }
}

Примечание: это не поможет, если вы только установите кодировку для запроса. Вы также должны установить его для ответа response.setCharacterEncoding (кодировка). Конфигурация в web.xml выглядит так

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>xyz.mypackage.CharacterEncodingFilter</filter-class>
    <init-param>
        <description>override any encodings from client</description>
        <param-name>ignore</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <description>the encoding to use</description>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>*.jsf</url-pattern>
</filter-mapping>

Теперь вам нужно добавить следующие системные свойства в standalone.xml сразу после закрывающего тега <extensions>:

1
2
3
4
<system-properties>
    <property name="org.apache.catalina.connector.URI_ENCODING" value="UTF-8"/>
    <property name="org.apache.catalina.connector.USE_BODY_ENCODING_FOR_QUERY_STRING" value="true"/>
</system-properties>

Из документа:

  • org.apache.catalina.connector.URI_ENCODING указывает кодировку символов, используемую для декодирования байтов URI, после% xx декодирования URL-адреса. Если не указано, будет использоваться ISO-8859-1.
  • org.apache.catalina.connector.USE_BODY_ENCODING_FOR_QUERY_STRING указывает, следует ли использовать кодировку, указанную в contentType, для параметров запроса URI вместо использования org.apache.catalina.connector.URI_ENCODING. Этот параметр присутствует для совместимости с Tomcat 4.1.x, где для параметров из URL-адреса также использовалась кодировка, указанная в contentType или явно заданная с использованием метода Request.setCharacterEncoding. Значение по умолчанию неверно.

JBoss теперь устанавливает кодировку символов для ответа и декодирует параметры URL с его помощью. Я надеюсь, что эта информация поможет вам сэкономить ваше время.