El formulario se envía, aparece el indicador y la consola dice que hay un token < inesperado en JSON en la posición 0. La página se carga bien, y por eso el primer impulso es culpar al analizador o al túnel. Normalmente no interviene ninguno de los dos: el envío es una petición distinta de la carga de la página, y ha vuelto con algo que no es JSON. Trabaja en el orden en que el navegador lo revela de verdad, porque las cuatro respuestas posibles necesitan cuatro correcciones distintas.

Paso 1: captura el envío que ocurrió realmente

Abre el panel Red antes de enviar, deja el registro configurado para conservar las entradas entre navegaciones y haz un envío de prueba inofensivo con una cuenta que tengas permitido usar. Selecciona la petición que inició el propio formulario, no la petición del documento de la página.

Ten cuidado con los filtros. Un filtro XHR o Fetch es cómodo, pero si el framework todavía envía mediante un iframe oculto o un formulario creado dinámicamente, el filtro ocultará la única petición que importa. Envía primero una vez sin filtro y mira qué apareció.

Para la petición elegida, anota seis cosas antes de interpretar nada: el método, la URL completa con la cadena de consulta, el estado, la cadena de redirecciones, el Content-Type de la respuesta y las primeras líneas del cuerpo. La referencia del panel Red de Chrome DevTools cubre las vistas Headers, Response e Initiator donde están esos datos, y los paneles equivalentes de otros navegadores muestran los mismos campos.

Paso 2: confirma que es la petición que crees

Una cantidad sorprendente de errores de JSON son en realidad errores de enrutamiento. Si el manejador del envío lanza una excepción antes de llamar a preventDefault, el navegador hace un POST nativo del formulario a la dirección del atributo action, y el servidor responde con una página HTML completa. El manejador nunca se ejecuta, así que nunca se pidió JSON.

Compara la URL del panel con la URL que llama tu JavaScript. Busca una redirección que termine en otro sitio, una barra final que falte o que sobre, un desajuste de método en el que el manejador envía GET y el extremo acepta POST, o un formulario que envía a una ruta relativa desde una página que se movió. Sigue la cadena de redirecciones hasta el final y anota la URL final, no la primera.

Después revisa el iniciador. Si la petición vino de una navegación de documento y no de tu script, ya has encontrado el problema, y ningún cambio en un analizador de respuesta va a ayudar.

Paso 3: clasifica el resultado en cuatro categorías

Cada resultado pertenece exactamente a una de estas, y la categoría decide dónde mirar después.

What you seeCategoryWhere to look
Request never finishes, TLS or connection errorNo usable responseEndpoint reachability, certificate, front-end timeout
Request completes, script gets an opaque failureAccess blockedCross-origin policy, credentials mode, missing response header
200 with an HTML body or a login formWrong representationRedirect, expired session, route fallback, error handler
Body begins with a notice then valid JSONWrong representationServer-side warning output before serialisation
Valid JSON, framework rejects itContract mismatchEnvelope shape, field names, value types

Las filas centrales son las que la gente diagnostica mal, porque el estado es 200. Una página de inicio de sesión alcanzada tras una redirección es una respuesta HTTP perfectamente buena y un documento JSON muy malo. El tipo de contenido application/json no lo arregla: es una etiqueta, y un cuerpo mal etiquetado sigue sin poder analizarse. Acceso bloqueado es la fila que parece una petición completada: el panel muestra un estado, pero la política de origen cruzado retiene el cuerpo, así que para el script que llama es tan inútil como un tiempo de espera agotado.

La cuarta fila es igual de común en pilas antiguas de PHP y de frameworks. Un aviso de obsolescencia impreso antes de la carga codificada produce un cuerpo que ningún analizador JSON aceptará, y a menudo ese aviso es toda la explicación.

Paso 4: lee el error del analizador al pie de la letra

El texto del error nombra el primer carácter que rompió el análisis, lo que suele identificar la categoría sin ninguna conjetura.

Error text (Chrome/V8)What it means
Unexpected token < in JSON at position 0The body starts with markup: an HTML page or an error document
Unexpected end of JSON inputEmpty body, or the response was truncated
Unexpected token o in JSON at position 1You parsed something already parsed, typically an object rather than text
Unexpected token uThe body starts with the bare word undefined, usually an empty response rendered as a string

Un cuerpo vacío con un 200 es un caso propio: el extremo se ejecutó, no produjo nada y algo más abajo lo tomó como un éxito. Es un fallo de contrato de la aplicación y no de transporte, y su sitio está en el paso siguiente, no en el proxy. Firefox y Safari formulan los mismos cuatro fallos de otra manera, así que compara por el carácter o por el cuerpo vacío y no por la cadena exacta.

Paso 5: corrige la capa que señalan las pruebas

Para un problema de enrutamiento, corrige la petición: arregla el action, evita que el manejador caiga, haz que coincidan el extremo y el método, y vuelve a probar. Para un problema de representación, corrige lo que produjo el cuerpo y averigua por qué se devuelve un documento de error donde se esperaban datos. Para un problema de contrato, lee la estructura real que el framework espera para la versión que ejecutas y da forma a la respuesta conforme a ella en lugar de aflojar el cliente.

Una respuesta con acceso bloqueado necesita su propia pasada, porque la petición puede ser correcta y el cuerpo puede no llegar nunca a tu código. Compara el Access-Control-Allow-Origin de la respuesta con el Origin exacto que envió el navegador, y recuerda que un comodín no satisface una petición con credenciales. Empareja credentials: 'include' en el cliente con Access-Control-Allow-Credentials: true en el servidor, y comprueba si la llamada usó el modo no-cors, donde un cuerpo opaco es el resultado documentado y no un defecto.

Sustituir el analizador por algo permisivo es la única corrección que hay que evitar. Evaluar la respuesta como código, o quitar texto hasta que se analice, oculta el desajuste de contrato y añade una superficie de inyección a cambio de silencio. Igualmente, comprobar el estado por separado del cuerpo es obligatorio: un 200 que lleva un objeto de error de nivel de aplicación es normal en muchas API y debe tratarse leyendo la carga útil.

Cuando necesites ayuda de otra persona, comparte un registro mínimo — método, URL, estado, URL final tras las redirecciones, tipo de contenido de la respuesta, forma del cuerpo y el contrato esperado — en lugar de una exportación en bruto. Los archivos de red contienen cookies, tokens, cadenas de consulta y los datos personales que había en el formulario, y un saneador automático no es una revisión.

  • Captura la petición sin filtro antes de cambiar cualquier código.
  • Confirma que el iniciador fue tu script y que la URL final es tu extremo.
  • Clasifica la respuesta antes de tocar el analizador.
  • Corrige enrutamiento, acceso, representación o contrato, y nunca aflojando el analizador.

Artículos relacionados