Estoy tratando de recuperar datos JSON de una URL, pero aparece el siguiente error:
Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n,\t) is allowed between tokens
Mi código:
final URI uri = new URIBuilder(UrlConstants.SEARCH_URL) .addParameter("keywords", searchTerm) .addParameter("count", "50") .build(); node = new ObjectMapper().readTree(new URL(uri.toString())); <<<<< THROWS THE ERROR
La URL construida es, por ejemplo, https://www.example.org/api/search.json?keywords=iphone&count=50
¿Qué está fallando aquí? ¿Y cómo puedo analizar estos datos con éxito?
Importaciones:
import com.google.appengine.repackaged.org.codehaus.jackson.JsonNode; import com.google.appengine.repackaged.org.codehaus.jackson.map.ObjectMapper; import com.google.appengine.repackaged.org.codehaus.jackson.node.ArrayNode; import org.apache.http.client.utils.URIBuilder;
ejemplo de respuesta
{ meta: { indexAllowed: false }, products: { products: [ { id: 1, name: "Apple iPhone 6 16GB 4G LTE GSM Factory Unlocked" }, { id: 2, name: "Apple iPhone 7 8GB 4G LTE GSM Factory Unlocked" } ] } }
Recibí este mismo problema y descubrí que fue causado por Content-Encoding: gzip
. La aplicación cliente (donde se lanzó la excepción) no pudo manejar esta codificación de contenido. FWIW, la aplicación cliente estaba usando io.github.openfeign:feign-core:9.5.0
, y esta biblioteca parece tener algunos problemas relacionados con la compresión ( enlace ).
Puede intentar agregar el encabezado Accept-Encoding: identity
a su solicitud, sin embargo, no todos los servidores web/aplicaciones web están configurados correctamente, y algunos parecen ignorar este encabezado. Consulte esta pregunta para obtener más detalles sobre cómo evitar el contenido comprimido con gzip.
Tuve un problema similar. Después de investigar un poco, descubrí que restTemplate usa SimpleClientHttpRequestFactory, que no admite la codificación gzip. Para habilitar la codificación gzip para su respuesta, deberá configurar una nueva fábrica de solicitudes para el resto del objeto de plantilla: HttpComponentsClientHttpRequestFactory.
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
El mensaje debería ser bastante autoexplicativo:
Hay un carácter ilegal (en este caso, el código de carácter 31, es decir, el código de control "Separador de unidades") en el JSON que está procesando.
En otras palabras, los datos que está recibiendo no son JSON adecuados.
Fondo:
La especificación JSON ( RFC 7159 ) dice:
- Gramática JSON
Un texto JSON es una secuencia de tokens. El conjunto de tokens incluye seis caracteres estructurales, cadenas, números y tres nombres literales.
[...]
Se permiten espacios en blanco insignificantes antes o después de cualquiera de los seis caracteres estructurales.
ws = *(
%x20 / ; Espacio
%x09 / ; Pestaña horizontal
%x0A / ; Salto de línea o Nueva línea
%x0D); Retorno de carro
En otras palabras: JSON puede contener espacios en blanco entre los tokens ("tokens" que significan la parte del JSON, es decir, listas, cadenas, etc.), pero "espacio en blanco" se define para significar solo los caracteres Espacio, Tabulador, Avance de línea y Retorno de carro. .
Su documento contiene algo más (código 31) donde solo se permiten espacios en blanco, por lo tanto, no es JSON válido.
Para analizar esto:
Desafortunadamente, la biblioteca de Jackson que está utilizando no ofrece una forma de analizar estos datos mal formados. Para analizar esto con éxito, tendrá que filtrar el JSON antes de que Jackson lo maneje.
Probablemente tendrá que recuperar el (pseudo-)JSON usted mismo del servicio REST, usando HTTP estándar, por ejemplo, java.net.HttpUrlConnection . Luego filtre adecuadamente los caracteres "malos" y pase la cadena resultante a Jackson. Cómo hacer esto exactamente depende de cómo uses a Jackson.
Siéntase libre de hacer preguntas separadas si tiene problemas :-).