Ввод Unicode, полученный через компоненты ввода PrimeFaces, поврежден

Когда я все еще использовал PrimeFaces v2.2.1, я мог набирать ввод Unicode, например китайский, с компонентом ввода PrimeFaces, таким как <p:inputText> а также <p:editor>и получить входные данные в хорошем состоянии в методе управляемого компонента.

Однако после того, как я обновился до PrimeFaces v3.1.1, все эти символы стали Mojibake или вопросительными знаками. Хорошо подходит только латинский ввод, это искаженные символы китайского, арабского, иврита, кириллицы и т. Д.

Как это вызвано и как я могу решить это?

1 ответ

Решение

Вступление

Обычно JSF/Facelets устанавливает кодировку символов параметра запроса в UTF-8 по умолчанию уже при создании / восстановлении представления. Но если какой-либо параметр запроса был запрошен до того, как представление было создано / восстановлено, тогда уже слишком поздно устанавливать правильную кодировку символов. Параметры запроса будут проанализированы только один раз.

Ошибка кодировки PrimeFaces

То, что это не удалось в PrimeFaces 3.x после обновления с 2.x, вызвано новым isAjaxRequest() переопределить в PrimeFaces PrimePartialViewContext который проверяет параметр запроса:

@Override
public boolean isAjaxRequest() {
    return getWrapped().isAjaxRequest()
            || FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().containsKey("javax.faces.partial.ajax");
}

По умолчанию isAjaxRequest() (один из Mojarra / MyFaces, как приведенный выше код PrimeFaces получил getWrapped()) проверяет заголовок запроса следующим образом, что не влияет на кодирование параметров запроса, поскольку параметры запроса не будут анализироваться при получении заголовка запроса:

    if (ajaxRequest == null) {
        ajaxRequest = "partial/ajax".equals(ctx.
            getExternalContext().getRequestHeaderMap().get("Faces-Request"));
    }

Тем не менее isAjaxRequest() может быть вызван любым слушателем фазы или слушателем системных событий или какой-либо фабрикой приложений перед созданием / восстановлением представления. Таким образом, когда вы используете PrimeFaces 3.x, параметры запроса будут проанализированы до того, как будет установлена ​​правильная кодировка символов, и, следовательно, будет использоваться кодировка сервера по умолчанию, обычно ISO-8859-1. Это все испортит.

Решения

Есть несколько способов это исправить:

  1. Используйте фильтр сервлетов, который устанавливает ServletRequest#setCharacterEncoding() с UTF-8. Установка кодировки ответа с помощью ServletResponse#setCharacterEncoding() Кстати, это не нужно, поскольку эта проблема не будет затронута.

    @WebFilter("/*")
    public class CharacterEncodingFilter implements Filter {
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
            request.setCharacterEncoding("UTF-8");
            chain.doFilter(request, response);
        }
    
        // ...
    }
    

    Вам нужно только принять во внимание, что HttpServletRequest#setCharacterEncoding() устанавливает только кодировку для параметров запроса POST, а не для параметров запроса GET. Для параметров запроса GET вам все равно необходимо настроить его на уровне сервера.

    Если вы используете библиотеку утилит JSF OmniFaces, такой фильтр уже имеется, CharacterEncodingFilter, Просто установите его, как показано ниже web.xml как первая запись фильтра:

    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.omnifaces.filter.CharacterEncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

  2. Переконфигурируйте сервер для использования UTF-8 вместо ISO-8859-1 в качестве кодировки по умолчанию. В случае Glassfish это было бы вопросом добавления следующей записи в <glassfish-web-app> из /WEB-INF/glassfish-web.xml файл:

    <parameter-encoding default-charset="UTF-8" />
    

    Tomcat не поддерживает это. Имеет URIEncoding приписывать <Context> запись, но это относится только к запросам GET, но не к запросам POST.


  3. Сообщите об этом как об ошибке в PrimeFaces. Есть ли на самом деле какая-либо законная причина для проверки того, что HTTP-запрос является ajax-запросом, проверяя параметр запроса вместо заголовка запроса, как это делается для стандартного JSF и, например, jQuery? PrimeFaces ' core.js JavaScript делает это. Было бы лучше, если бы он установил его как заголовок запроса XMLHttpRequest,


Решения, которые НЕ работают

Возможно, вы наткнетесь на приведенные ниже "решения" где-то в Интернете при исследовании этой проблемы. Эти решения никогда не будут работать в этом конкретном случае. Объяснение следует.

  • Установка пролога XML:

    <?xml version='1.0' encoding='UTF-8' ?>
    

    Это только говорит синтаксическому анализатору XML использовать UTF-8 для декодирования источника XML перед построением дерева XML вокруг него. Анализатор XML, фактически используемый Facelts, является SAX во время сборки представления JSF. Эта часть не имеет ничего общего с HTTP-запросом / ответом.

  • Установка метатега HTML:

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

    Метатег HTML игнорируется, когда страница обслуживается через HTTP через http(s):// URI. Он используется только тогда, когда клиент сохраняет страницу в виде файла HTML на локальной дисковой системе, а затем открывает ее file:// URI в браузере.

  • Настройка HTML-формы принимает атрибут charset:

    <h:form accept-charset="UTF-8">
    

    Современные браузеры игнорируют это. Это действует только в браузере Microsoft Internet Explorer. Даже тогда он делает это неправильно. Никогда не используйте это. Все настоящие веб-браузеры вместо этого будут использовать атрибут charset, указанный в Content-Type заголовок ответа. Даже MSIE сделает это правильно, если вы не укажете accept-charset приписывать.

  • Установка аргумента JVM:

    -Dfile.encoding=UTF-8
    

    Это используется только Oracle(!) JVM для чтения и анализа исходных файлов Java.

Другие вопросы по тегам