"Error de sintaxis: token inesperado < en JSON en la posición 0"
En un componente de la aplicación React que maneja feeds de contenido similares a Facebook, me encuentro con un error:
Feed.js:94 undefined "parsererror" "SyntaxError: token inesperado < en JSON en la posición 0
Me encontré con un error similar que resultó ser un error tipográfico en el HTML dentro de la función de renderizado, pero ese no parece ser el caso aquí.
Lo que es más confuso es que revertí el código a una versión anterior que funciona y sigo recibiendo el error.
Feed.js:
import React from 'react';
var ThreadForm = React.createClass({
getInitialState: function () {
return {author: '',
text: '',
included: '',
victim: ''
}
},
handleAuthorChange: function (e) {
this.setState({author: e.target.value})
},
handleTextChange: function (e) {
this.setState({text: e.target.value})
},
handleIncludedChange: function (e) {
this.setState({included: e.target.value})
},
handleVictimChange: function (e) {
this.setState({victim: e.target.value})
},
handleSubmit: function (e) {
e.preventDefault()
var author = this.state.author.trim()
var text = this.state.text.trim()
var included = this.state.included.trim()
var victim = this.state.victim.trim()
if (!text || !author || !included || !victim) {
return
}
this.props.onThreadSubmit({author: author,
text: text,
included: included,
victim: victim
})
this.setState({author: '',
text: '',
included: '',
victim: ''
})
},
render: function () {
return (
<form className="threadForm" onSubmit={this.handleSubmit}>
<input
type="text"
placeholder="Your name"
value={this.state.author}
onChange={this.handleAuthorChange} />
<input
type="text"
placeholder="Say something..."
value={this.state.text}
onChange={this.handleTextChange} />
<input
type="text"
placeholder="Name your victim"
value={this.state.victim}
onChange={this.handleVictimChange} />
<input
type="text"
placeholder="Who can see?"
value={this.state.included}
onChange={this.handleIncludedChange} />
<input type="submit" value="Post" />
</form>
)
}
})
var ThreadsBox = React.createClass({
loadThreadsFromServer: function () {
$.ajax({
url: this.props.url,
dataType: 'json',
cache: false,
success: function (data) {
this.setState({data: data})
}.bind(this),
error: function (xhr, status, err) {
console.error(this.props.url, status, err.toString())
}.bind(this)
})
},
handleThreadSubmit: function (thread) {
var threads = this.state.data
var newThreads = threads.concat([thread])
this.setState({data: newThreads})
$.ajax({
url: this.props.url,
dataType: 'json',
type: 'POST',
data: thread,
success: function (data) {
this.setState({data: data})
}.bind(this),
error: function (xhr, status, err) {
this.setState({data: threads})
console.error(this.props.url, status, err.toString())
}.bind(this)
})
},
getInitialState: function () {
return {data: []}
},
componentDidMount: function () {
this.loadThreadsFromServer()
setInterval(this.loadThreadsFromServer, this.props.pollInterval)
},
render: function () {
return (
<div className="threadsBox">
<h1>Feed</h1>
<div>
<ThreadForm onThreadSubmit={this.handleThreadSubmit} />
</div>
</div>
)
}
})
module.exports = ThreadsBox
En las herramientas para desarrolladores de Chrome, el error parece provenir de esta función:
loadThreadsFromServer: function loadThreadsFromServer() {
$.ajax({
url: this.props.url,
dataType: 'json',
cache: false,
success: function (data) {
this.setState({ data: data });
}.bind(this),
error: function (xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
con la línea console.error(this.props.url, status, err.toString()
subrayada.
Como parece que el error tiene algo que ver con la extracción de datos JSON del servidor, intenté comenzar desde una base de datos en blanco, pero el error persiste. El error parece aparecer en un bucle infinito, presumiblemente porque React intenta conectarse continuamente al servidor y finalmente bloquea el navegador.
EDITAR:
Revisé la respuesta del servidor con las herramientas de desarrollo de Chrome y el cliente REST de Chrome, y los datos parecen ser JSON adecuados.
EDITAR 2:
Parece que, aunque el punto final API previsto de hecho devuelve los datos y el formato JSON correctos, React está sondeando http://localhost:3000/?_=1463499798727
en lugar del esperado http://localhost:3001/api/threads
.
Estoy ejecutando un servidor de recarga en caliente de paquete web en el puerto 3000 con la aplicación express ejecutándose en el puerto 3001 para devolver los datos del backend. Lo frustrante aquí es que funcionó correctamente la última vez que trabajé en ello y no puedo encontrar qué podría haber cambiado para romperlo.
La redacción del mensaje de error corresponde a lo que obtienes de Google Chrome cuando ejecutas JSON.parse('<...')
. Sé que dijiste que el servidor se está configurando Content-Type:application/json
, pero me hacen creer que el cuerpo de la respuesta es en realidad HTML.
Feed.js:94 undefined "parsererror" "SyntaxError: Unexpected token < in JSON at position 0"
con la línea
console.error(this.props.url, status, err.toString())
subrayada.
En realidad, se err
lanzó dentro jQuery
y se le pasó como una variable err
. La razón por la que esa línea está subrayada es simplemente porque es ahí donde la está registrando.
Le sugeriría que agregue a su registro. Observe las xhr
propiedades reales (XMLHttpRequest) para obtener más información sobre la respuesta. Intente agregar console.warn(xhr.responseText)
y lo más probable es que vea el HTML que se recibe.
Estás recibiendo HTML (o XML) del servidor, pero le dataType: json
dice a jQuery que lo analice como JSON. Consulte la pestaña "Red" en las herramientas de desarrollo de Chrome para ver el contenido de la respuesta del servidor.
SyntaxError: token inesperado < en JSON en la posición 0
Obtendrá un archivo HTML (o XML) en lugar de json.
Los archivos HTML comienzan con <!DOCTYPE html>
.
"Logré" este error al olvidar https://
en mi fetch
método:
fetch(`/api.github.com/users/${login}`)
.then(response => response.json())
.then(setData);
Verifiqué mi corazonada:
Registré la respuesta como texto en lugar de JSON.
fetch(`/api.github.com/users/${login}`)
.then(response => response.text())
.then(text => console.log(text))
.then(setData);
Sí, un archivo html.
Solución:
Solucioné el error agregando nuevamente el https://
en mi fetch
método.
fetch(`https://api.github.com/users/${login}`)
.then(response => response.json())
.then(setData)
.catch(error => (console.log(error)));
Esto terminó siendo un problema de permisos para mí. Estaba intentando acceder a una URL para la que no tenía autorización con CanCan, por lo que la URL se cambió a users/sign_in
. La URL redirigida responde a HTML, no a json. El primer carácter de una respuesta HTML es <
.