Compréhension fondamentale de l'encodage des caractères
Lors du développement web avec des servlets Java, l'affichage incorrect des caractères chinois (appelé couramment "caractères fantaisie" ou "乱码") est un problème fréquent. Ce phénomène provient principalement d'une incohérence entre les schémas d'encodage utilisés lors de la transmission des données entre le navigateur et le serveur.
Notions de base à retenir :
- Les systèmes d'exploitation chinois utilisent généralement GBK comme encodage par défaut (compatible avec GB2312).
- Les points critiques d'encodage sont : la requête envoyée par le client, la réponse générée par le serveur, et l'interprétation par le navigateur.
- En Java, on peut obtenir l'encodage par défaut via
Charset.defaultCharset(). - Les méthodes
getOutputStream()etgetWriter()deHttpServletResponsene doivent pas être utilisées simultanément. - La méthode
String.getBytes()utilise l'encodage par défaut sauf si spécifié (ex:getBytes("UTF-8")).
Mécanisme d'encodage/décodage
L'encodage consiste à convertir un texte en une séquence d'octets selon une table prédéfinie (UTF-8, GBK, etc.). Le décodage est l'opération inverse. Pour que les données soient correctement interprétées, le processus de décodage doit utiliser la même table que celui utilisé pour l'encodage.
Solutions aux erreurs d'encodage
Problèmes liés aux requêtes (Request)
Pour les requêtes GET
Les paramètres GET sont inclus dans l'URL. Les navigateurs modernes encodent souvent ces paramètres en UTF-8, mais le serveur Tomcat, s'il n'est pas configuré, les interprète en ISO-8859-1.
Solution 1 : Configuration côté serveur
Modifier le fichier server.xml de Tomcat pour imposer l'UTF-8 sur les URI :
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8"
useBodyEncodingForURI="true" />
Cette configuration garantit que les paramètres URI sont correctement décodés en UTF-8.
Solution 2 : Recodage manuel
Si la configuration serveur n'est pas possible, corriger manuellement l'encodage dans le code :
String nom = request.getParameter("nom");
if (nom != null) {
nom = new String(nom.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
}
Solution 3 : Encodage côté client
Utiliser URLEncoder pour préparer les données sensibles (comme les noms de fichiers) :
String cheminFichier = "/documents/简历.pdf";
String nomFichier = cheminFichier.substring(cheminFichier.lastIndexOf('/') + 1);
response.setHeader("Content-Disposition",
"attachment; filename*=UTF-8''" + URLEncoder.encode(nomFichier, "UTF-8"));
Pour les requêtes POST
Les données POST sont contenues dans le corps de la requête. Il suffit d'indiquer au serveur l'encodage attendu avant de lire les paramètres :
// À placer impérativement avant getParameter()
request.setCharacterEncoding("UTF-8");
String donnee = request.getParameter("champ");
Note : Cette méthode n'affecte que les données du corps (POST), pas les paramètres d'URL (GET).
Problèmes liés aux réponses (Response)
Le désordre d'affichage survient quand le navigateur interprète mal les données envoyées par le serveur.
Étape 1 : Indiquer le type MIME et l'encodage
Informer le navigateur du format et de l'encodage des données :
response.setContentType("text/html; charset=UTF-8");
Étape 2 : Gérer l'encodage selon le flux utilisé
-
Avec
getWriter()(flux de caractères) : ``` response.setContentType("text/html; charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("Bonjour, 世界 !"); -
Avec
getOutputStream()(flux d'octets) : ``` response.setContentType("text/plain; charset=UTF-8"); OutputStream os = response.getOutputStream(); os.write("Message en chinois".getBytes(StandardCharsets.UTF_8)); os.flush();
Bonnes pratiques et astuces
- Toujours définir
contentTypeen début de traitement de réponse. - Utiliser
StandardCharsets.UTF_8plutôt que des chaînes littérales ("UTF-8") pour éviter les erreurs. - Valider que les pages HTML source utilisent également UTF-8 via la balise
<meta charset="utf-8">. - Consulter l'encodage actuel avec
response.getContentType(). - Éviter d'utiliser
print("<meta ...>")pour fixer l'encodage ; privilégier les en-têtes HTTP.