Utilice java.util.Base64 de java8 para informar "java.lang.IllegalArgumentException: Illegal base64 character d"

Referencia original: https://blog.csdn.net/java_4_ever/article/details/80978089

Quiero agradecerles nuevamente por la originalidad. También encontré una solución al problema, pero no entendí la razón. Aprendí el artículo anterior.

¿Se descubre el problema después de que la producción se puso en línea?

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]

Originalmente del código de producción, se ha utilizado sun.misc.BASE64Decoder / BASE64Encoder, debido a que estas dos clases no son clases oficiales, el escaneo de sonar, la compilación maven y algunos complementos de especificación de código provocarán algunos mensajes de advertencia, etc., java8 y Proporcionó el java.util.Base64 oficial. Tenía limpieza de código, pero fui impulsivo e inmediatamente comencé a hacerlo. Después de un tiempo, la prueba se puso en línea y causó un error.

Aquí es por qué no hay prueba, porque solo se reemplaza el método base64, sentirás que no hay ningún problema y no es complicado pensar en ello. La otra es que escribí un caso de prueba que usa java.util.Base64 para Encoder. Usa java.util.Base64 para decodificar los datos después del codificador. No hay problema en la prueba, y el código se considera correcto. ¡Pero el problema está precisamente aquí! Debido a que la operación real en el entorno de producción no es consistente con mi caso, en la producción estamos accediendo a los datos base64 de la organización asociada para decodificar, pero la otra parte no está usando la codificación Base64 de java8, ¡así que ocurrió una excepción!

Publique mi solución aquí: uso original

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

Descripción general
Base64 es un formato de codificación de cadenas que utiliza 64 caracteres de AZ, az, 0-9, "+" y "/" para codificar los caracteres originales (y el carácter de relleno "="). Un carácter en sí es un byte, es decir, 8 bits, y un carácter codificado por base64 solo puede representar 6 bits de información. Es decir, la codificación de información de 3 bytes en la cadena original se convierte en información de 4 bytes. La función principal de Base64 es cumplir con los requisitos de transmisión de MIME. 
En Java8, la codificación Base64 se ha convertido en un estándar para las bibliotecas de clases de Java, y se integra un codificador y decodificador de codificación Base64.

Problema Descubrí
accidentalmente que al usar el decodificador Base64 incorporado de jdk8 para analizar, java.lang.IllegalArgumentException: carácter base64 ilegal, se lanzará una excepción. 
Esto es muy extraño, porque el texto original está codificado usando el codificador en jdk7, por lo que esta incompatibilidad no debería ocurrir teóricamente.

Programa de prueba
Escribamos un programa para probar dónde está el problema.

El programa de prueba utiliza un texto original relativamente largo, principalmente porque este problema solo ocurre cuando el texto original es más largo.Si el texto original es más corto (la longitud de bytes no excede 57), entonces este problema no ocurrirá.

1 Utilice jdk7 para codificar:

import sun.misc.BASE64Encoder;
clase pública TestBase64JDK7 {     Cadena final estática privada TEST_STRING = "0123456789,0123456789,0123456789,0123456789,0123456789,0123456789,0123456789";     public static void main (String [] args) {         BASE64Encoder base64Encoder = new BASE64Encoder ();         String 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 codifica utilizando la anteriormente decodificación de resultados.:

java.util.Base64 importación;
public class TestBase64JDK8 {     void Main (args String []) {public static         base64Result String = "MDEyMzQ1Njc4Oe 8jDAxMjM0NTY3ODnvvIwwMTIzNDU2Nzg577yMMDEyMzQ1Njc4Oe + + 8jDAxMjM0 \ n" +                 "NTY3ODnvvIwwMTIzNDU2Nzg577yMMDEyMzQ1Njc4OQ ==";         . Base64.getDecoder () de decodificación (base64Result );     } } 1 2 3 4 5 6 7 8 4 El resultado es como se describe al principio, se lanzará una excepción:














Excepción en el hilo "principal" java.lang.IllegalArgumentException: carácter base64 ilegal a
    en java.util.Base64 $ Decoder.decode0 (Base64.java:714)
    en java.util.Base64 $ Decoder.decode (Base64.java:526)
    en java.util.Base64 $ Decoder.decode (Base64.java:549)
    en com.francis.TestBase64JDK8.main (TestBase64JDK8.java:14)
1
2
3
4
5
¿Podría decirse que jdk7 y jdk8 tienen alguna diferencia en base64 ¿mismo? ? ?

5 Continúe mirando la codificación del texto original por jdk8:

import java.util.Base64;
clase pública TestBase64JDK8 {     Cadena final estática privada 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 = Longitud se pueden comparar con las siguientes conclusiones a partir de
1
a 4 de codificación de la base:

El resultado de codificación de jdk7 contiene
saltos de línea; el resultado de codificación de jdk8 no contiene
saltos de línea; jdk8 no puede decodificar resultados de codificación que incluyen saltos de línea ;
el resultado de codificación de jdk8 usa jdk7 para decodificar, no hay ningún problema y no hay más demostraciones.

Ahora, la causa del problema es básicamente clara, porque el resultado de codificación de jdk7 contiene saltos de línea, lo que provoca que se produzca una excepción al decodificar jdk8. 
Pero, ¿por qué hay tanta diferencia? ¿El estándar base64 se usa de manera diferente?

Solución de problemas
Continúe resolviendo el problema, comience con las anotaciones de la clase y vea si lo entiende incorrectamente.

1 Echemos un vistazo a las anotaciones de la clase Base64 en jdk8. Estos son solo algunos contenidos clave:

/ **
 * Esta clase consta exclusivamente de métodos estáticos para obtener
 * codificadores y decodificadores para el esquema de codificación Base64. La
 * implementación de esta clase admite los siguientes tipos de Base64
 * como se especifica en
 * <a href="http://www.ietf.org/rfc/rfc4648.txt"> RFC 4648 </a> y
 * <a href = "http://www.ietf.org/rfc/rfc2045.txt"> RFC 2045 </a>.
 *
 * <ul>
 * <li> <a name="basic"> <b> Básico </b> </a>
 * <p> Utiliza "El Alfabeto Base64" como se especifica en la Tabla 1 de
 * RFC 4648 y RFC 2045 para la operación de codificación y decodificación.
 * El codificador no agrega ningún carácter de salto de línea (separador de línea)
 *. El decodificador rechaza datos que contienen caracteres.
 El Alfabeto Base64 Fuera *. </ P> </ Li>
 ...
 * @author Xueming Shen
 * @Since 1.8
 * /
. 1
2.
3.
4.
5.
6.
7.
8.
9
10.
11
12 es
13 es
14
15
16.
17
18 es
. 19
en el sentido de que :

Esta clase contiene el método de codificación y el método de decodificación del formato de codificación base64, y la implementación se implementa de acuerdo con los dos protocolos rfc4648 y rfc2045.
Las operaciones de codificación y decodificación se basan en el "Alfabeto Base64" especificado en la "Tabla 1" de los dos protocolos. El codificador no agregará saltos de línea y el decodificador solo procesará datos dentro del rango de 'El Alfabeto Base64'. Si no está dentro de este rango, el decodificador se negará a procesarlos.
1
2
vea aquí, puede comprender por qué el resultado de la codificación no contiene jdk8 para el viaje. 

Además, básicamente puede adivinar por qué jdk8 no puede decodificar el resultado de codificación de jdk7 (el carácter de nueva línea no debería estar en el alfabeto base64).

2 Echemos un vistazo al alfabeto base64 en los dos estándares (la tabla en los dos estándares es la misma):

                         Tabla 1:
        Valor alfabético de Base 64 Valor de codificación Valor de codificación Valor de codificación Codificación
            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 (almohadilla) =
           15 P 32 g 49 x
           16 Q 33 h 50 y
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
no contiene un carácter de nueva línea, lo que puede explicar por qué jdk8 no puede decodificar el resultado de codificación que contiene una nueva línea.

3 Echemos un vistazo a la anotación de clase de sun.misc.BASE64Encoder en jdk7:

   Esta clase implementa un codificador de caracteres BASE64 como se especifica en RFC1521. 
   Esta RFC es parte de la especificación MIME publicada por el Grupo de trabajo de ingeniería de Internet (IETF). 
   A diferencia de otros esquemas de codificación, no hay nada en esta codificación que indique dónde comienza o dónde comienza un búfer. extremos. 
   Esto significa que el texto codificado simplemente comenzar con la primera línea de texto codificada y al final con la última línea de texto codificado.
1
2
3
4
Esta aplicación se basa en RFC1521, y hay ninguna codificación o limitaciones de decodificación en los comentarios de la clase instrucción de.

4 Luego, continúe mirando las partes clave de rfc1521 (enlace: https://tools.ietf.org/html/rfc1521).

En la sección 5.2. Codificación de transferencia de contenido Base64, se encuentran los siguientes contenidos:

   El flujo de salida (bytes codificados) debe representarse en líneas de no
      más de 76 caracteres cada una. El
      software de decodificación debe ignorar todos los saltos de línea u otros caracteres que no se encuentran en la Tabla 1. En los
      datos base64 , los caracteres distintos a los de la Tabla 1, los saltos de línea y otros
      espacios en blanco probablemente indiquen un error de transmisión, sobre el cual un
      mensaje de advertencia o incluso un rechazo de mensaje podría ser apropiado
      en algunas circunstancias.
1
2
3
4
5
6
7
这里 明确 规定 了 :

Cada línea del resultado de la codificación no puede exceder los 76 caracteres; los
caracteres decodificados deben estar en el rango de: Tbale 1 (es decir, el alfabeto base64 mencionado anteriormente), saltos de línea y caracteres de espacio en blanco;
es por eso que el resultado de codificación de jdk7 contiene saltos de línea. 
De esta forma, en base a las anotaciones de clase y el contenido del protocolo rfc, podrás explicar las conclusiones anteriores obtenidas a través del código de prueba, y podrás entender por qué ocurre este problema.

El paquete que comienza con 'un' no pertenece a la especificación de Java, pero es la implementación de Sun, por lo que el método de codificación base64 en jdk7 no es una especificación de Java.

Solución
Entonces, cómo resolver este problema: 
1. Use la clase org.apache.commons.codec.binary.Base64 en el paquete común de apache para codificar y decodificar; 
2. Elimine los saltos de línea después de la codificación o antes de la decodificación; 
3. Codificación y Utilice la misma versión de jdk para decodificar;

Otras bibliotecas de Base64
Eche un vistazo a cómo otras bibliotecas manejan base64. 
1. Apache Common

La clase org.apache.commons.codec.binary.Base64 en Apache Common se implementa en base a rfc2045. Según los comentarios de la clase, podemos entender que esta implementación ignora todos los caracteres que no están en el rango del alfabeto base64 al decodificar, por lo que la implementación puede manejar la inclusión Resultado de la codificación Base64 del carácter de nueva línea. 
Al mismo tiempo, este tipo de método de codificación proporciona parámetros para especificar si se deben agregar saltos de línea cuando la longitud del resultado de la codificación supera los 76 caracteres. De forma predeterminada, los saltos de línea no se agregan.

Spring Core
Spring Core proporciona la clase Base64Utils, que es solo una clase de herramienta y no implementa ningún protocolo.

Java.util.Base64 se usa preferiblemente en codificación y decodificación de clase java8;
si java.util.Base64 no existe, use org.apache.commons.codec.binary.Base64;
si no está presente, se le dará el
protocolo Jane De los
pasos de solución de problemas anteriores, podemos ver que la parte base64 de rfc1521, rfc2045 y rfc4648 parece ser diferente. A continuación, echemos un vistazo breve a cómo estos tres protocolos regulan los saltos de línea de la codificación base64.

rfc1521 (enlace: https://tools.ietf.org/html/rfc1521) 
Este protocolo trata sobre MIME, y Base64 es un tipo de codificación compatible con MIME. Contenido clave 5.2 El capítulo Codificación de transferencia de contenido Base64 se ha explicado brevemente anteriormente, principalmente para estipular: la longitud de cada línea del resultado de la codificación y el rango de caracteres decodificados. 
El acuerdo ha sido eliminado. 
jdk7 implementa base64 basado en este protocolo, por lo que el resultado de la codificación contendrá saltos de línea.

MIME: Extensiones de correo de Internet multipropósito, tipo de extensión de correo de Internet multipropósito. Es un estándar de Internet que se utilizó por primera vez en los sistemas de correo electrónico y luego se aplicó a los navegadores. El servidor le dirá al navegador el tipo de datos multimedia que envían, y el medio de notificación es indicar el tipo MIME de los datos multimedia.

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

El acuerdo también es sobre MIME, es una versión actualizada de rfc1521, el contenido clave es 6.8. Sección de Codificación de Transferencia de Contenido Base64, en la que no hay diferencia entre la longitud del resultado de codificación y el rango de caracteres decodificados y rfc1521.

rfc4648

El acuerdo trata sobre la codificación base16, base32 y base64. La descripción de la longitud de cada línea del resultado de la codificación se encuentra en el capítulo 3.1. Saltos de línea en datos codificados:

   MIME se usa a menudo como referencia para la codificación base 64. Sin embargo,
      MIME no define "base 64" per se, sino una "
      codificación de transferencia de contenido base 64 " para su uso dentro de MIME. Como tal, MIME impone un
      límite en la longitud de la línea de datos codificados en base 64 a 76 caracteres. MIME
      hereda la codificación de Privacy Enhanced Mail (PEM) [3], indicando
      que es "prácticamente idéntica"; sin embargo, PEM utiliza una longitud de línea de
      64 caracteres. Los límites de MIME y PEM se deben a límites dentro de
      SMTP.

   Las implementaciones NO DEBEN agregar saltos de línea a datos codificados en base a menos que
      la especificación que hace referencia a este documento indique explícitamente a los
      codificadores base que agreguen saltos de línea después de un número específico de caracteres.
1
2
3
4
5
6
7
8
9
10
11
12
大意 是 :

   El protocolo MIME generalmente se conoce como protocolo base64. Pero el protocolo MIME no define 'base64', sino que define 'codificación de transferencia de contenido base64'. Por lo tanto, MIME limita la longitud de los datos codificados en base64 a 76 caracteres.
   ... Las
   restricciones de longitud MIME y PEM se utilizan para SMTP.
   La implementación de este protocolo no puede agregar un carácter de nueva línea en el resultado de la codificación, a menos que se cite la implementación del documento y se indique claramente que se agrega un carácter de nueva línea después de una cierta longitud.
1
2
3
4
La clase Base64 de jdk8 se implementa en base a rfc2045 y rfc4648. De acuerdo con el contenido del protocolo mencionado anteriormente, se puede determinar que el resultado de codificación de esta clase no contendrá saltos de línea, y en los comentarios de la clase se indica claramente que no se agregará Salto de línea.
--------------------- 
Autor: java_4_ever 
Fuente: CSDN 
Original: https: //blog.csdn.net/java_4_ever/article/details/80978089 
Descargo de responsabilidad: este artículo Artículo original para el blogger, adjunte un enlace a la publicación del blog si lo reimprime.

Supongo que te gusta

Origin blog.csdn.net/kevin_mails/article/details/87878601
Recomendado
Clasificación