L'entrée Unicode récupérée via les composants d'entrée PrimeFaces est corrompue
-
10-12-2019 - |
Question
Lorsque j'utilisais encore PrimeFaces v2.2.1, j'étais capable de saisir une entrée Unicode telle que le chinois avec un composant d'entrée PrimeFaces tel que <p:inputText>
et <p:editor>
, et récupérez l'entrée en bon état dans la méthode du bean géré.
Cependant, après la mise à niveau vers PrimeFaces v3.1.1, tous ces personnages deviennent des Mojibake ou des points d'interrogation.Seule la saisie latine fonctionne correctement, ce sont les caractères chinois, arabes, hébreux, cyrilliques, etc. qui deviennent mal formés.
Comment est-ce dû et comment puis-je le résoudre ?
La solution
Introduction
Normalement, JSF/Facelets définira le codage des caractères du paramètre de demande sur UTF-8 par défaut dès la création/restauration de la vue.Mais si un paramètre de requête est demandé avant la vue a été créée/restaurée, il est alors trop tard pour définir le codage de caractères approprié.Les paramètres de la requête ne seront analysés qu'une seule fois.
Échec de l'encodage PrimeFaces
L'échec de PrimeFaces 3.x après la mise à niveau à partir de 2.x est dû au nouveau isAjaxRequest()
remplacer dans PrimeFaces PrimePartialViewContext
qui vérifie un paramètre de requête :
@Override
public boolean isAjaxRequest() {
return getWrapped().isAjaxRequest()
|| FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().containsKey("javax.faces.partial.ajax");
}
Par défaut, le isAjaxRequest()
(celui de Mojarra/MyFaces, comme le code PrimeFaces ci-dessus a obtenu par getWrapped()
) vérifie l'en-tête de la requête comme suit, ce qui n'affecte pas le codage des paramètres de la requête, car les paramètres de la requête ne seront pas analysés lorsqu'un en-tête de requête est obtenu :
if (ajaxRequest == null) {
ajaxRequest = "partial/ajax".equals(ctx.
getExternalContext().getRequestHeaderMap().get("Faces-Request"));
}
Cependant, le isAjaxRequest()
peut être appelé par n'importe quel écouteur de phase ou d'événement système ou une fabrique d'applications avant la vue a été créée/restaurée.Ainsi, lorsque vous utilisez PrimeFaces 3.x, les paramètres de la requête seront analysés avant le codage de caractères approprié a été défini et utilise donc le codage par défaut du serveur qui est généralement ISO-8859-1.Cela va tout gâcher.
Solutions
Il existe plusieurs façons de résoudre ce problème :
Utiliser un filtre de servlets qui définit
ServletRequest#setCharacterEncoding()
avec UTF-8.Définition du codage de la réponse parServletResponse#setCharacterEncoding()
est d'ailleurs inutile car il ne sera pas affecté par ce problème.@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); } // ... }
Il suffit de prendre en compte que
HttpServletRequest#setCharacterEncoding()
définit uniquement le codage des paramètres de requête POST, pas pour les paramètres de requête GET.Pour les paramètres de requête GET, vous devrez toujours le configurer au niveau du serveur.Si vous utilisez la bibliothèque d'utilitaires JSF OmniFaces, un tel filtre est déjà fourni, le
CharacterEncodingFilter
.Installez-le simplement comme ci-dessous dansweb.xml
comme première entrée de filtre :<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>
Reconfigurez le serveur pour utiliser UTF-8 au lieu d'ISO-8859-1 comme codage par défaut.Dans le cas de Glassfish, il s'agirait d'ajouter l'entrée suivante à
<glassfish-web-app>
de la/WEB-INF/glassfish-web.xml
déposer:<parameter-encoding default-charset="UTF-8" />
Tomcat ne le prend pas en charge.Il a la
URIEncoding
attribut dans<Context>
entrée, mais cela s'applique uniquement aux requêtes GET, pas aux requêtes POST.Signalez-le comme un bug à PrimeFaces.Y a-t-il vraiment une raison légitime de vérifier que la requête HTTP est une requête ajax en vérifiant un paramètre de requête au lieu d'un en-tête de requête comme vous le feriez pour le JSF standard et par exemple jQuery ?Les PrimeFaces
core.js
JavaScript fait cela.Ce serait mieux s'il le définissait comme en-tête de requête deXMLHttpRequest
.
Des solutions qui ne fonctionnent PAS
Peut-être tomberez-vous sur les « solutions » ci-dessous quelque part sur Internet en enquêtant sur ce problème.Ces solutions ne fonctionneront jamais dans ce cas précis.L’explication suit.
Paramétrage du prologue XML :
<?xml version='1.0' encoding='UTF-8' ?>
Cela indique uniquement à l'analyseur XML d'utiliser UTF-8 pour décoder la source XML avant de construire l'arborescence XML autour d'elle.L'analyseur XML actuellement utilisé par Facelts est SAX pendant JSF voir le temps de construction.Cette partie n'a absolument rien à voir avec l'encodage des requêtes/réponses HTTP.
Définition de la balise méta HTML :
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
La balise méta HTML est ignorée lorsque la page est servie sur HTTP via un
http(s)://
URI.Il n'est utilisé que lorsque la page est enregistrée par le client sous forme de fichier HTML sur le système de disque local, puis rouverte par unfile://
URI dans le navigateur.Définition du formulaire HTML acceptant l'attribut charset :
<h:form accept-charset="UTF-8">
Les navigateurs modernes l'ignorent.Cela n'a d'effet que dans le navigateur Microsoft Internet Explorer.Même dans ce cas, il le fait mal.Ne l'utilisez jamais.Tous les vrais navigateurs Web utiliseront à la place l'attribut charset spécifié dans le
Content-Type
en-tête de la réponse.Même MSIE le fera correctement tant que vous ne spécifiez pas leaccept-charset
attribut.Définition de l'argument JVM :
-Dfile.encoding=UTF-8
Ceci n'est utilisé que par la JVM Oracle (!) Pour lire et analyser les fichiers source Java.