Subida fallida: encuentra la causa antes de reintentar
Cuando falle una subida, abre el panel Red del navegador y reproduce el fallo una vez con un archivo pequeño y válido de prueba. Localiza la solicitud de subida, inspecciona su respuesta y relaciónala con los registros del servidor antes de cambiar límites o añadir reintentos. Esta guía está dirigida a desarrolladores que depuran un sistema de subida web existente; necesitas acceso al código que maneja sus solicitudes y a sus registros para confirmar la causa.
Captura un intento fallido
Abre DevTools antes de subir el archivo. Activa Conservar registro si el envío provoca una navegación a otra página; luego inspecciona la URL, el método, el estado, la carga útil, la respuesta y los tiempos de la solicitud. La guía del panel Red de Chrome muestra dónde encontrar estos detalles. Revisa cada solicitud del flujo de subida: la obtención de una URL de subida, la transferencia de bytes y la finalización de la subida pueden fallar por separado.
Anota la hora, el tamaño y el tipo de archivo, el estado y cualquier ID de solicitud que proporcione el servicio. Usa ese ID para correlacionar los registros del proxy y de la aplicación. Si no hay un ID, usa la marca de tiempo, la ruta y la cuenta de prueba. No incluyas cookies, encabezados de autorización, URL firmadas ni contenidos de archivos en los informes compartidos.
Compara el archivo que falla con uno pequeño del mismo formato compatible. Si ambos fallan, el tamaño por sí solo no explica el fallo. Si solo falla el archivo más grande, inspecciona los datos de tamaño y tiempos antes de determinar si la causa es un límite o una solicitud interrumpida.
Localiza la capa que falla
Considera el estado como una pista. La respuesta y los registros correspondientes identifican qué componente rechazó la solicitud; un proxy y una aplicación pueden devolver el mismo estado.
| Qué observas | Qué revisar después |
|---|---|
| No aparece ninguna solicitud de subida | La validación del cliente, la selección de archivos y las excepciones de JavaScript. Comprueba si falló una solicitud anterior en un flujo de varios pasos. |
401 o 403 | La autenticación, el permiso de subida, las credenciales caducadas y la validación CSRF. Lee el código de error del servicio. |
413 | Los límites del cuerpo de la solicitud en el proxy y los límites de archivos en la aplicación. Localiza el componente que registró el rechazo. |
400, 415 o 422 | El nombre de campo esperado, la codificación de la solicitud y el resultado de la validación del archivo en la aplicación. |
fetch() se rechaza sin una respuesta legible | Los detalles de la consola del navegador, CORS, los errores de conexión y la cancelación. Comprueba si el servidor recibió la solicitud. |
500, 502, 503 o 504 | Los errores de la aplicación, la disponibilidad del servicio ascendente, los tiempos de espera agotados y los errores de almacenamiento en los registros del servidor. |
Una respuesta 2xx, pero ningún archivo utilizable | El contenido de la respuesta, las redirecciones, la finalización y el estado de cualquier tarea de procesamiento. |
Estas son vías de investigación, no una correspondencia universal entre estados y causas. Por
ejemplo, 413 significa que el contenido de la solicitud es demasiado grande,
mientras que 503 describe una indisponibilidad temporal del servicio;
no identifica un disco lleno. Consulta las
definiciones de los estados HTTP.
Mantén visibles los fallos HTTP en tu código
fetch() se resuelve ante respuestas de error HTTP.
Una promesa rechazada y una respuesta con ok: false son observaciones distintas.
Comprueba response.ok antes de analizar un cuerpo: de lo contrario, una página de
error HTML de un proxy puede convertirse en un error de análisis de JSON engañoso.
Para un manejador de subidas multipart existente, esta función auxiliar de TypeScript conserva esa
distinción. Acepta el archivo seleccionado y la URL de tu manejador, y envía un campo llamado
file. Úsala solo cuando esto coincida con tu API; conserva la autenticación
y el manejo de CSRF que requiere tu aplicación al adaptar la solicitud. El manejador ya debe estar
en ejecución.
async function uploadForDiagnosis(
file: File | undefined,
url: string,
): Promise<Response | undefined> {
if (file === undefined) return
const body = new FormData()
body.append('file', file)
const response = await fetch(url, { method: 'POST', body })
if (!response.ok) {
throw new Error(`Upload returned HTTP ${response.status}`)
}
return response
}
Pasa el File seleccionado y la URL de subida desde tu manejador de envío
existente, espera el resultado y maneja allí el rechazo. Si no hay una selección, no se envía nada;
un archivo vacío sí genera una solicitud. Upload returned HTTP 413 significa que llegó una
respuesta HTTP legible. Un error de red o de CORS del navegador rechaza el propio
fetch() y se propaga a través de esta función auxiliar. La función no programa
reintentos. La respuesta devuelta aún necesita la validación de éxito habitual de tu API; por ejemplo,
una redirección de inicio de sesión que termina en 200 no demuestra que se
haya aceptado un archivo.
No establezcas Content-Type manualmente para esta solicitud
FormData. El navegador proporciona el delimitador multipart;
sobrescribir el encabezado puede impedir el análisis.
Mantén deshabilitados los envíos duplicados mientras tu manejador de subidas existente esté pendiente.
Modifica el componente que rechazó la subida
Rastrea un límite de tamaño a lo largo de la ruta de la solicitud
Supón que un archivo pequeño se sube correctamente y uno más grande recibe
413. Si el proxy registra el rechazo y la aplicación no tiene ninguna
solicitud correspondiente, investiga primero el proxy. Confirma que el registro de solicitudes de la
aplicación esté habilitado antes de considerar la ausencia de una entrada como evidencia.
En NGINX, client_max_body_size
limita el cuerpo de la solicitud y se puede establecer en el nivel
http, server o location.
Revisa la configuración de la ruta real de subida. Una solicitud multipart contiene campos y
delimitadores además del archivo, por lo que el límite del cuerpo de la solicitud necesita un margen
por encima del tamaño de archivo permitido. Aumentar un límite de la aplicación no puede eliminar
un límite previo del proxy.
Si el límite documentado del producto debería admitir el archivo, ajusta la capa que lo rechaza dentro de tu presupuesto de almacenamiento y recursos. De lo contrario, conserva el límite y explícalo en la interfaz. Vuelve a probar el archivo original, uno de tamaño apenas inferior al permitido y otro que lo supere. El último debe seguir siendo rechazado.
Lee el motivo del rechazo de la aplicación
Ante una respuesta de solicitud mal formada o archivo no compatible, compara la solicitud con el
contrato del manejador. ¿Espera un campo multipart llamado file, un campo
con otro nombre o un cuerpo sin procesar? ¿Incluye la solicitud los metadatos requeridos? No cambies
la codificación ni la extensión del archivo hasta que la respuesta o el registro identifique una
discrepancia.
Si el formato real del archivo no es compatible, elige un archivo de origen compatible o conviértelo
con una herramienta adecuada. Cambiar .exe por
.jpg no convierte el contenido. Vuelve a probar con un archivo cuya validez
esté confirmada y conserva un archivo no permitido como prueba negativa.
Distingue CORS de una conexión fallida
Un error genérico de obtención de datos del navegador no identifica la causa. Inspecciona el error específico de la consola junto con el panel Red y los registros del servidor.
- Si falla una solicitud de verificación previa
OPTIONS, revisa el origen, el método y los encabezados de solicitud permitidos por el servidor. El navegador puede detenerse antes de enviar el archivo. - Si la subida llega al servidor, pero su respuesta carece de los encabezados CORS requeridos, JavaScript no puede leer esa respuesta. Es posible que el servidor ya haya aceptado el archivo. Comprueba el estado almacenado antes de reintentar.
- Si el navegador informa de un error de conexión o de certificado, investiga esa conexión. Si tu código abortó la solicitud, localiza la cancelación o el tiempo de espera agotado que lo provocó.
Configura CORS en el servidor que responde, incluidas sus respuestas de error. Las solicitudes entre
orígenes con credenciales necesitan un origen permitido explícito y los ajustes de credenciales
adecuados; * no los sustituye. La
guía de CORS de MDN explica las comprobaciones de verificación previa
y de respuesta. Vuelve a probar desde el origen del navegador original con las condiciones de
autenticación originales. Una solicitud cURL exitosa no demuestra que CORS funcione en el navegador.
No uses mode: 'no-cors' como solución. Produce una respuesta opaca cuyo estado y
cuerpo no puede inspeccionar tu código. Vuelve a probar tanto una subida aceptada como un rechazo
intencional: ambas respuestas deben seguir siendo legibles para el origen permitido.
Rastrea un error del servidor hasta la operación que falló
Una respuesta 5xx necesita un error correspondiente del lado del servidor.
Identifica si el fallo ocurrió al analizar la solicitud, escribir un archivo temporal, almacenar el
objeto final o ejecutar un procesamiento posterior. Para el almacenamiento en el sistema de archivos,
inspecciona el espacio libre, la cuota, la ruta de destino real y los permisos de la cuenta de
servicio. Revisa también el almacenamiento temporal; que el directorio final permita escritura no
demuestra que el analizador de subidas pueda guardar datos temporalmente.
Usa el error subyacente para elegir la solución. Por ejemplo, los
errores EACCES y ENOENT
de Node distinguen un fallo de permisos de una ruta inexistente. Corrige la ruta o el permiso
específico del servicio; luego repite la misma subida y verifica los bytes almacenados. No permitas
que cualquiera escriba en el directorio de subidas para ocultar un problema de permisos. Si una
puerta de enlace informa de que un servicio ascendente no está disponible, confirma el estado de la
aplicación antes de cambiar los ajustes del disco o los tiempos de espera.
Añade la capacidad de reanudar cuando el problema sean las interrupciones
Una vez que funcionen las subidas válidas, las interrupciones de conexión repetidas pueden justificar el uso de subidas reanudables. Con el protocolo tus, un cliente puede consultar el desplazamiento almacenado y continuar desde allí con un servidor compatible. Dividir un archivo en fragmentos en el navegador no proporciona por sí solo ese acuerdo sobre desplazamientos, almacenamiento y finalización.
La capacidad de reanudar no corrige un archivo no válido, una solicitud denegada, la configuración de CORS ni el almacenamiento agotado. Si la adoptas, prueba la interrupción y la recuperación, y compara el archivo completado con el original. Usa las implementaciones del protocolo tus para elegir un cliente y un servidor compatibles.
Verifica la solución sin eliminar las medidas de protección
Ejecuta de nuevo el caso que fallaba originalmente; luego prueba un archivo pequeño válido y otro no permitido elegido deliberadamente. Confirma la respuesta HTTP esperada, el resultado de aceptación de la aplicación y el archivo almacenado o el resultado final del procesamiento. Para una subida sin modificaciones, compara los bytes descargados o una suma de comprobación con el original. Una barra de progreso completada solo describe la etapa de transferencia que mide.
Mantén la validación del tamaño y del contenido del lado del servidor aunque la interfaz los compruebe primero. Trata los nombres de archivo y los tipos MIME declarados como no confiables, genera nombres para el almacenamiento, restringe el acceso y aplica un análisis de seguridad o la neutralización de contenido cuando el tipo de archivo y el riesgo lo requieran. La guía de subida de archivos de OWASP describe estos controles. Un error útil indica al usuario qué cambiar y proporciona a soporte un ID de solicitud, mientras que las rutas internas, las trazas de pila y las credenciales quedan fuera de la respuesta.
