Utilisez java.util.Base64 de java8 pour signaler "java.lang.IllegalArgumentException: Illegal base64 character d"

Référence originale: https://blog.csdn.net/java_4_ever/article/details/80978089

Je tiens à vous remercier encore pour l'originalité. J'ai également trouvé une solution au problème, mais je n'ai pas compris la raison. J'ai appris l'article ci-dessus.

Le problème est-il découvert après la mise en ligne de la production:

java.lang.IllegalArgumentException: Illegal base64 character d
        at java.util.Base64$Decoder.decode0(Base64.java:714) ~[na:1.8.0_45]
        at java.util.Base64$Decoder.decode(Base64.java:526) ~[na:1.8.0_45]
        at java.util.Base64$Decoder.decode(Base64.java:549) ~[na:1.8.0_45]

À l'origine du code de production, sun.misc.BASE64Decoder / BASE64Encoder a été utilisé, car ces deux classes ne sont pas des classes officielles, l'analyse du sondeur, la compilation maven et certains plug-ins de spécification de code entraîneront des invites d'avertissement, etc., java8 et J'ai fourni le java.util.Base64 officiel. J'avais la propreté du code, mais j'étais impulsif et j'ai immédiatement commencé à le faire. Après un certain temps, le test s'est mis en ligne et a provoqué un bogue.

Voici pourquoi il n'y a pas de test, car seule la méthode base64 est remplacée, vous aurez l'impression qu'il n'y a pas de problème, et ce n'est pas compliqué d'y penser.L'autre est que j'ai écrit un cas de test qui utilise java.util.Base64 pour Encoder. Utilisez java.util.Base64 pour décoder les données après le codeur. Il n'y a pas de problème dans le test, et le code est considéré comme correct. Mais le problème est précisément là! Parce que le fonctionnement réel dans l'environnement de production n'est pas cohérent avec mon cas, dans la production, nous accédons aux données base64 de l'organisation partenaire à décoder, mais l'autre partie n'utilise pas le codage Base64 de java8, donc une exception s'est produite!

Postez ma solution ici: utilisation originale

Base64.getDecoder().decode() 修改为 Base64.getMimeDecoder().decode()

Présentation
Base64 est un format de codage de chaîne qui utilise 64 caractères AZ, az, 0-9, "+" et "/" pour coder les caractères d'origine (et le caractère de remplissage "="). Un caractère lui-même est un octet, c'est-à-dire 8 bits, et un caractère encodé en base64 ne peut représenter que 6 bits d'information. Autrement dit, le codage d'informations sur 3 octets dans la chaîne d'origine devient des informations sur 4 octets. La fonction principale de Base64 est de répondre aux exigences de transmission de MIME. 
Dans Java8, le codage Base64 est devenu un standard pour les bibliothèques de classes Java, et un codeur et un décodeur de codage Base64 sont intégrés.

Problème J'ai
accidentellement découvert que lors de l'utilisation du décodeur Base64 intégré de jdk8 pour l'analyse, java.lang.IllegalArgumentException: Caractère base64 illégal, une exception sera levée. 
C'est très étrange, car le texte original est encodé à l'aide de l'encodeur de jdk7, donc cette incompatibilité ne devrait pas se produire en théorie.

Programme de test
Écrivons un programme pour tester où se situe le problème.

Le programme de test utilise un texte d'origine relativement long, principalement parce que ce problème se produit uniquement lorsque le texte d'origine est plus long. Si le texte d'origine est plus court (la longueur d'octet ne dépasse pas 57), ce problème ne se produira pas.

1 Utilisez jdk7 pour encoder:

import sun.misc.BASE64Encoder;
public class TestBase64JDK7 {     private static final String TEST_STRING = "0123456789,0123456789,0123456789,0123456789,0123456789,0123456789,0123456789";     public static void main (String [] args) {         BASE64Encoder base64Encoder = new BASE64Encoder ();         Chaîne base64Result = base64Encoder.encode (TEST_STRING.getBytes ());         System.out.println (base64Result);     } } 1 2 3 4 5 6 7 8 9 2 jdk7 编码 结果 :
















+ + 8jDAxMjM0 8jDAxMjM0NTY3ODnvvIwwMTIzNDU2Nzg577yMMDEyMzQ1Njc4Oe MDEyMzQ1Njc4Oe
NTY3ODnvvIwwMTIzNDU2Nzg577yMMDEyMzQ1Njc4OQ ==
1.
2
3 jdk8 codé en utilisant le dessus des résultats de décodage.:

java.util.Base64 importation;
public class TestBase64JDK8 {     public static void main (String [] args) {         chaîne base64Result = "MDEyMzQ1Njc4Oe 8jDAxMjM0NTY3ODnvvIwwMTIzNDU2Nzg577yMMDEyMzQ1Njc4Oe + + 8jDAxMjM0 \ n-" +                 "NTY3ODnvvIwwMTIzNDU2Nzg577yMMDEyMzQ1Njc4OQ ==";         . Base64.getDecoder () décodage (base64Result );     } } 1 2 3 4 5 6 7 8 4 Le résultat est comme décrit au début, une exception sera levée:














Exception dans le thread "main" java.lang.IllegalArgumentException: Caractère base64 illégal a
    à java.util.Base64 $ Decoder.decode0 (Base64.java:714)
    à java.util.Base64 $ Decoder.decode (Base64.java:526)
    à java.util.Base64 $ Decoder.decode (Base64.java:549)
    à com.francis.TestBase64JDK8.main (TestBase64JDK8.java:14)
1
2
3
4
5
Peut-on dire que jdk7 et jdk8 ont une différence dans le traitement de base64 même? ? ?

5 Continuez à regarder l'encodage du texte original par jdk8:

import java.util.Base64;
public class TestBase64JDK8 {     private static final String TEST_STRING = "0123456789,0123456789,0123456789,0123456789,0123456789,0123456789,0123456789";     public static void main (String [] args) {         String base64Result = Base64.getEncoder (). encodeToString (TEST_STRING.getBytes ());         System.out.println (base64Result);     } } 1 2 3 4 5 6 7 8 6 jdk8 编码 结果 :














MDEyMzQ1Njc4Oe + 8jDAxMjM0NTY3ODnvvIwwMTIzNDU2Nzg577yMMDEyMzQ1Njc4Oe + 8jDAxMjM0NTY3ODnvvIwwMTIzNDU2NzgQ577yMMDEyMOQ = Longueur peuvent être comparées aux conclusions suivantes
1
à 4 Codage de base:

Le résultat du codage de jdk7 contient des
sauts de ligne; le résultat du codage de jdk8 ne contient pas de
sauts de ligne; jdk8 ne peut pas décoder les résultats du codage qui incluent des sauts de ligne ;
le résultat du codage de jdk8 utilise jdk7 pour le décodage, il n'y a aucun problème, et aucune autre démonstration.

Maintenant, la cause du problème est fondamentalement claire, car le résultat du codage de jdk7 contient des sauts de ligne, ce qui provoque la levée d'une exception lors du décodage de jdk8. 
Mais pourquoi y a-t-il une telle différence? La norme base64 est-elle utilisée différemment?

Dépannage
Continuez à résoudre le problème, commencez par les annotations de classe et voyez si vous ne le comprenez pas correctement.

1 Jetons un coup d'œil aux annotations de classe Base64 dans jdk8. Voici seulement quelques contenus clés:

/ **
 * Cette classe se compose exclusivement de méthodes statiques pour obtenir
 * des encodeurs et des décodeurs pour le schéma d'encodage Base64.
 * L' implémentation de cette classe prend en charge les types suivants de Base64
 * comme spécifié dans
 * <a href="http://www.ietf.org/rfc/rfc4648.txt"> RFC 4648 </a> et
 * <a href = "http://www.ietf.org/rfc/rfc2045.txt"> RFC 2045 </a>.
 *
 * <ul>
 * <li> <a name="basic"> <b> De base </b> </a>
 * <p> Utilise "l'alphabet de base64" comme spécifié dans le tableau 1 de la
 * RFC 4648 et de la RFC 2045 pour l'opération d'encodage et de décodage.
 * L'encodeur n'ajoute aucun caractère de saut de ligne (séparateur de ligne)
 *. Le décodeur rejette les données contenant des caractères
 L'alphabet Base64 extérieur *. </ P> </ Li>
 ...
 * @author Xueming Shen
 * @Depuis 1.8
 * /
. 1
2.
3.
4.
5.
6.
7.
8.
9
10.
11
12 est
13 est
14
15
16.
17
18 est
. 19
à l'effet que :

Cette classe contient la méthode de codage et la méthode de décodage du format de codage base64, et l'implémentation est implémentée conformément aux deux protocoles rfc4648 et rfc2045.
Les opérations de codage et de décodage sont basées sur l '"Alphabet Base64" spécifié dans le "Tableau 1" des deux protocoles. L'encodeur n'ajoutera aucun saut de ligne et le décodeur ne traitera que les données comprises dans la plage de «l'alphabet base64». Si elles ne sont pas dans cette plage, le décodeur refusera de les traiter.
1
2
voir ici vous pouvez comprendre pourquoi le résultat de codage ne contient pas jdk8 pour le voyage. 

De plus, vous pouvez essentiellement deviner pourquoi jdk8 ne peut pas décoder le résultat de l'encodage de jdk7 (le caractère de nouvelle ligne ne doit pas être dans l'alphabet base64).

2 Jetons un coup d'œil à l'alphabet base64 dans les deux normes (le tableau des deux normes est le même):

                         Tableau 1:
        Valeur de l' alphabet de base 64 Valeur de codage Valeur de codage Valeur de codage Codage
            0 A 17 R 34 i 51 z
            1 B 18 S 35 j 52 0
            2 C 19 T 36 k 53 1
            3 D 20 U 37 l 54 2
            4 E 21 V 38 m 55 3
            5 F 22 W 39 n 56 4
            6 G 23 X 40 o 57 5
            7 H 24 Y 41 p 58 6
            8 I 25 Z 42 q 59 7
            9 J 26 a 43 r 60 8
           10 K 27 b 44 s 61 9
           11 L 28 c 45 t 62 +
           12 M 29 d 46 u 63/13
           N 30 e 47 v
           14 O 31 f 48 w (tampon) =
           15 P 32 g 49 x
           16 Q 33 h 50 ans
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ne contient pas de caractère de nouvelle ligne, ce qui peut expliquer pourquoi jdk8 ne peut pas décoder le résultat de l'encodage qui contient une nouvelle ligne.

3 Jetons un coup d'œil à l'annotation de classe de sun.misc.BASE64Encoder dans jdk7:

   Cette classe implémente un encodeur de caractères BASE64 comme spécifié dans la RFC1521. 
   Cette RFC fait partie de la spécification MIME publiée par l'IETF (Internet Engineering Task Force). 
   Contrairement à certains autres schémas de codage, il n'y a rien dans ce codage qui indique où un tampon commence ou extrémités. 
   Cela signifie que le texte codé simplement commencer par la première ligne de texte codé et à la fin de la dernière ligne de texte codé.
1
2
3
4
Cette mise en œuvre est basée sur RFC1521, et il n'y a pas de codage ou de contraintes de décodage dans les commentaires de classe instruction de.

4 Continuez ensuite à examiner les éléments clés de rfc1521 (lien: https://tools.ietf.org/html/rfc1521).

Dans la section 5.2. Base64 Content-Transfer-Encoding, il y a le contenu suivant:

   Le flux de sortie (octets codés) doit être représenté sur des lignes ne
      dépassant pas 76 caractères chacune. Tous les sauts de ligne ou autres caractères
      absents du tableau 1 doivent être ignorés par le logiciel de décodage. Dans les
      données base64 , des caractères autres que ceux du tableau 1, des sauts de ligne et d'autres
      espaces blancs indiquent probablement une erreur de transmission, pour laquelle un
      message d'avertissement ou même un rejet de message peut être approprié
      dans certaines circonstances.
1
2
3
4
5
6
7
这里 明确 规定 了 :

Chaque ligne du résultat de l'encodage ne peut pas dépasser 76 caractères; les
caractères décodés doivent être dans la plage de: Tbale 1 (c'est-à-dire l'alphabet base64 mentionné précédemment), les sauts de ligne et les espaces blancs;
c'est pourquoi le résultat de l'encodage de jdk7 contient des sauts de ligne. 
De cette façon, en fonction des annotations de classe et du contenu du protocole rfc, vous pouvez expliquer les conclusions ci-dessus obtenues via le code de test et comprendre pourquoi ce problème se produit.

Le paquet commençant par 'un' n'appartient pas à la spécification Java, mais est l'implémentation de Sun, donc la méthode de codage base64 dans jdk7 n'est pas une spécification Java.

Solution
Alors, comment résoudre ce problème: 
1. Utilisez la classe org.apache.commons.codec.binary.Base64 dans le package commun apache pour coder et décoder; 
2. Supprimez les sauts de ligne après le codage ou avant le décodage; 
3. Codage et Utilisez la même version de jdk pour le décodage;

Autres bibliothèques Base64
Jetez un œil à la manière dont les autres bibliothèques gèrent base64. 
1. Apache Common

La classe org.apache.commons.codec.binary.Base64 dans Apache Common est implémentée sur la base de rfc2045. D'après les commentaires de la classe, nous pouvons comprendre que cette implémentation ignore tous les caractères qui ne sont pas dans la plage de l'alphabet base64 lors du décodage, donc l'implémentation peut gérer l'inclusion Résultat du codage en base64 du caractère de nouvelle ligne. 
Dans le même temps, ce type de méthode de codage fournit des paramètres pour spécifier s'il faut ajouter des sauts de ligne lorsque la longueur du résultat de codage dépasse 76 caractères. Par défaut, les sauts de ligne ne sont pas ajoutés.

Spring Core
Spring Core fournit la classe Base64Utils, qui n'est qu'une classe d'outils et n'implémente aucun protocole.

Java.util.Base64 utilisé de préférence dans l'encodage et le décodage de classe java8;
si java.util.Base64 n'existe pas, utilisez org.apache.commons.codec.binary.Base64;
s'il n'est pas présent, le
protocole Jane sera attribué À partir des
étapes de dépannage ci - dessus, nous pouvons voir que la partie base64 de rfc1521, rfc2045 et rfc4648 semble être différente. Ensuite, examinons brièvement comment ces trois protocoles régulent les sauts de ligne de l'encodage base64.

rfc1521 (lien: https://tools.ietf.org/html/rfc1521) 
Ce protocole concerne MIME et Base64 est un type d'encodage pris en charge par MIME. Contenu clé 5.2 Le chapitre Encodage de transfert de contenu Base64 a été brièvement expliqué ci-dessus, principalement pour préciser: la longueur de chaque ligne du résultat de l'encodage et la plage de caractères décodés. 
L'accord a été supprimé. 
jdk7 implémente base64 sur la base de ce protocole, donc le résultat de l'encodage contiendra des sauts de ligne.

MIME: Extensions de messagerie Internet polyvalentes, type d'extension de messagerie Internet polyvalente. Il s'agit d'une norme Internet qui a été utilisée pour la première fois dans les systèmes de messagerie électronique, puis appliquée aux navigateurs. Le serveur indiquera au navigateur le type de données multimédias qu'il envoie, et le moyen de notification est d'indiquer le type MIME des données multimédias.

rfc2045 (lien: https://tools.ietf.org/html/rfc2045)

L'accord concerne également MIME, est une version mise à jour de rfc1521, le contenu clé est de 6,8. Base64 Content-Transfer-Encoding section, dans laquelle il n'y a aucune différence entre la longueur du résultat de l'encodage et la plage de caractères décodés et rfc1521.

rfc4648

L'accord porte sur l'encodage base16, base32 et base64. La description de la longueur de chaque ligne du résultat de l'encodage se trouve dans le chapitre 3.1. Saut de ligne dans les données encodées:

   MIME est souvent utilisé comme référence pour le codage en base 64. Cependant,
      MIME ne définit pas «base 64» en soi, mais plutôt «base 64 Content
      -Transfer-Encoding» à utiliser dans MIME. En tant que tel, MIME impose une
      limite de longueur de ligne des données codées en base 64 à 76 caractères. MIME
      hérite du codage de Privacy Enhanced Mail (PEM) [3], déclarant
      qu'il est "pratiquement identique"; cependant, PEM utilise une longueur de ligne de
      64 caractères. Les limites MIME et PEM sont toutes deux dues à des limites au sein de
      SMTP.

   Les mises en œuvre NE DOIVENT PAS ajouter de sauts de ligne aux données codées en base à moins que
      la spécification faisant référence à ce document n'indique explicitement
      aux codeurs de base d'ajouter des sauts de ligne après un nombre spécifique de caractères.
1
2
3
4
5
6
7
8
9
10
11
12
大意 是 :

   Le protocole MIME est généralement appelé protocole base64. Mais le protocole MIME ne définit pas «base64», mais définit plutôt «l'encodage de transfert de contenu base64». Par conséquent, MIME limite la longueur des données codées en base64 à 76 caractères.
   ... Les
   restrictions de longueur MIME et PEM sont utilisées pour SMTP.
   L'implémentation de ce protocole ne peut pas ajouter un caractère de nouvelle ligne dans le résultat du codage, sauf si l'implémentation du document est citée, et il est clairement indiqué qu'un caractère de nouvelle ligne est ajouté après une certaine longueur.
1
2
3
4
La classe Base64 de jdk8 est implémentée sur la base de rfc2045 et rfc4648. Selon le contenu du protocole listé ci-dessus, il peut être déterminé que le résultat de l'encodage de cette classe ne contiendra pas de sauts de ligne, et il est clairement indiqué dans les commentaires de classe qu'il ne sera pas ajouté Saut de ligne.
--------------------- 
Auteur: java_4_ever 
Source: CSDN 
Original: https: //blog.csdn.net/java_4_ever/article/details/80978089
Clause de non-  responsabilité: cet article Article original pour le blogueur, veuillez joindre un lien vers l'article du blog si vous le réimprimez!

Je suppose que tu aimes

Origine blog.csdn.net/kevin_mails/article/details/87878601
conseillé
Classement