Loading...

HTTP

Descripción

Motor low-level para la gestión de transacciones HTTP asíncronas basada en el objeto nativo XMLHttpRequest. Está diseñado como el componente base de transferencia de la arquitectura, ofreciendo control sobre el ciclo de vida de las peticiones, gestión de tiempos de espera (timeouts), cabeceras personalizadas, credenciales de origen cruzado y monitorización de flujos de subida y descarga de datos.

Librería: estructura.http.js

Documentación

1. Interfaz del Motor de Peticiones

La librería expone un único namespace global denominado _http que contiene la función principal de ejecución.


_http(options):

Inicia una transacción de red configurada según el objeto de propiedades provisto.


Sintaxis:

var req = _http({ url: './config.json' });
// req.abort();
// req.getXHR();

Devuelve de forma síncrona un objeto de control con los siguientes métodos de instancia:


  • abort(): Cancela la petición en progreso de manera inmediata y dispara el callback de interrupción si está definido.
  • getXHR(): Proporciona acceso directo al objeto XMLHttpRequest nativo subyacente para inspecciones detalladas o manipulaciones low-level.

2. Opciones de Configuración (options)

El argumento de configuración estructurado para la función _http() admite las siguientes propiedades:


Sintaxis:

_http({
	url: 'https://backend.com/api/v1/setData',
	method: 'POST',
	data: { 'a': '1', 'N': '...' }
});

  • url (String): La dirección de destino del recurso. Requerido.

    Nota: El motor no realiza una validación previa de la presencia de este parámetro; su omisión provocará una excepción nativa en el método open() del navegador.

  • method (String): El método HTTP de la transacción (ej. "GET", "POST", "PUT", "DELETE"). Por defecto es "GET".

  • headers (Object): Pares clave-valor que representan las cabeceras HTTP que serán inyectadas en la petición mediante setRequestHeader.

  • data (Any): Datos que se incluirán en el cuerpo de la solicitud. Admite por defecto null (si es omitido o undefined). Soporta cadenas de texto, representaciones JSON, instancias de FormData, objetos Blob o búferes binarios.

    Nota: Dado que la librería transmite este valor directamente al método de envío nativo sin transformaciones de tipo internas, el envío de objetos de JavaScript que deban procesarse como JSON requiere de la serialización explícita previa por parte del usuario mediante JSON.stringify(), así como la definición manual de la cabecera Content-Type: application/json. Por el contrario, si se transmiten instancias de FormData, se recomienda omitir la cabecera Content-Type en el objeto headers para que el navegador configure automáticamente el tipo multipart y el límite (boundary) adecuado.

  • timeout (Number): Límite de tiempo en milisegundos para la transacción. Si es 0 (valor por defecto), no se aplicará ningún límite de tiempo.

  • withCredentials (Boolean): Permite activar el uso de credenciales de sesión (cookies, cabeceras de autorización) en llamadas de origen cruzado (CORS) cuando se establece en true.

3. Métodos y Comportamiento de los Callbacks de Configuración (options)

El motor implementa un conjunto específico de devoluciones de llamada para interceptar las distintas etapas de la transacción:


Callbacks de Estado y Finalización:

  • onSuccess(responseText, xhr): Se invoca cuando la petición finaliza con éxito (readyState === 4 y código de estado HTTP estrictamente en el rango de 200 a 299). Recibe el texto de la respuesta y la instancia XHR activa.

  • onError(error, xhr): Se ejecuta ante fallos de red críticos, bloqueos de seguridad del navegador, respuestas con códigos de estado HTTP fuera del rango de éxito (incluyendo respuestas con código 3xx que no hayan sido redirigidas automáticamente por el agente de usuario, además de códigos 4xx y 5xx con estado superior a 0), o tiempos de espera agotados si no existe un controlador dedicado. Recibe una instancia de Error y el objeto XHR.

  • onHeadersReceived(headersString, xhr): Se activa de manera asíncrona en el momento en que las cabeceras de la respuesta han sido leídas por el cliente (readyState === 2). Recibe la cadena cruda de cabeceras obtenida por getAllResponseHeaders().

  • onReadyStateChange(readyState, status, xhr): Escucha directa y low-level acoplada al ciclo nativo de cambio de estado de la petición.

Callbacks de Progreso e Interrupción:

  • onProgress(loaded, total, percent): Se ejecuta de manera continua durante la transferencia del recurso de respuesta, siempre y cuando el servidor retorne el tamaño de la carga útil (propiedad de evento lengthComputable). Recibe los bytes descargados, los bytes totales y el porcentaje calculado.

    Nota: La disponibilidad de la propiedad lengthComputable depende de la presencia de la cabecera Content-Length en la respuesta del servidor. En su ausencia, el cálculo de progreso y porcentaje no podrá realizarse con precisión.

  • onUploadProgress(loaded, total, percent): Proporciona información sobre el estado de la subida de datos del cliente hacia el servidor. Se enlaza al objeto xhr.upload de manera automática si existe información de envío y progreso disponible.

  • onTimeout(xhr): Se invoca de manera específica al superarse el límite establecido en timeout. Si se omite, el motor canaliza el error a través de onError con una excepción detallada.

  • onAbort(xhr): Se ejecuta si la transacción es interrumpida de forma controlada mediante la llamada al método abort() de la instancia devuelta.

4. Mecanismos Internos y Flujos de Control

Detección de Conflictos de Observabilidad:

Para asegurar una trazabilidad limpia del flujo de red, el motor emite una advertencia en la consola si el desarrollador define de manera simultánea un callback genérico onReadyStateChange junto con los controladores granulares de ciclo de vida (onSuccess, onError o onHeadersReceived). Esta advertencia es de carácter informativo y no restringe la ejecución física de ninguno de los controladores; ambos flujos operarán de manera independiente y en paralelo, lo que podría generar ejecuciones redundantes de lógica si el desarrollador gestiona los mismos estados de manera duplicada.


Tratamiento de Errores Críticos y Código de Estado Cero (Status 0):

Las conexiones fallidas que no llegan a establecer comunicación con el servidor (como fallos de resolución DNS, pérdida física de conexión, restricciones estrictas de origen cruzado o bloqueos por CORS) no producen un código de estado HTTP estándar, reflejándose en un valor de status igual a 0. El motor captura estas anomalías a través del controlador nativo onerror y las redirige de manera unificada al callback onError bajo una excepción de fallo de red crítico. Debido a que el analizador de estados nativos (onreadystatechange) filtra y descarta de manera explícita códigos inferiores o iguales a cero (xhr.status > 0), se evita la duplicación del callback ante este tipo de incidencias de red.


Flujo de Ejecución en Cancelaciones (Abort):

La interrupción programada de la petición mediante la invocación del método de control abort() detiene la operación de red en curso de manera inmediata. Aunque esta acción puede modificar las propiedades nativas del objeto `XMLHttpRequest` (reduciendo temporalmente el código de estado a 0 y alterando el estado de transición), el motor intercepta el proceso a través de su controlador onabort. El flujo de validación evita que esta cancelación sea procesada como un error general de conexión, garantizando que solo se invoque el callback específico onAbort configurado en las opciones.


5. Ejemplos Prácticos de Implementación

Petición GET Estándar con Manejo de Datos:

_http({
	url: 'https://api.ejemplo.com/v1/usuarios',
	method: 'GET',
	onSuccess: function(respuesta, xhr) {
		try {
			var usuarios = JSON.parse(respuesta);
			console.log('Lista de usuarios procesada:', usuarios);
		}
		catch (e) {
			console.error('La respuesta no posee un formato JSON válido:', e);
		}
	},
	onError: function(err, xhr) {
		console.error('Ocurrió un error en la transferencia:', err.message);
	}
});

Petición POST asíncrona con Seguimiento de Carga y Límite de Tiempo:

var controlDescarga = _http({
	url: 'https://api.ejemplo.com/v1/archivos',
	method: 'POST',
	headers: {
		'Content-Type': 'application/json',
		'X-Client-Identifier': 'Estructura-App'
	},
	data: JSON.stringify({ archivoId: 'doc_09182' }),
	timeout: 10000,
	onUploadProgress: function(cargado, total, porcentaje) {
		console.log('Progreso del envío de datos: ' + porcentaje.toFixed(2) + '%');
	},
	onSuccess: function(respuesta, xhr) {
		console.log('Procesamiento completado con éxito:', respuesta);
	},
	onTimeout: function(xhr) {
		console.error('El servidor superó el límite de respuesta de 10 segundos.');
	},
	onError: function(err, xhr) {
		console.error('No se pudo completar el envío:', err.message);
	}
});

Interrupción Programada de una Petición:

var peticion = _http({
	url: 'https://api.ejemplo.com/v1/stream-datos',
	onSuccess: function(respuesta, xhr) {
		console.log('Datos recibidos:', respuesta);
	},
	onAbort: function(xhr) {
		console.log('La transacción fue cancelada antes de su finalización.');
	}
});

// Cancelación de la llamada de red ante una acción específica del usuario
document.querySelector('#cancelar-accion').addEventListener('click', function() {
	peticion.abort();
});

Adaptación a Entornos Modernos mediante Promesas (ES6+):

Aunque el diseño original de la librería utiliza un modelo de callbacks para maximizar la compatibilidad y el control granular low-level, puede integrarse fácilmente con el flujo de Promesas estándar de JavaScript para habilitar el uso de async/await:

function solicitarRecurso(configuracion) {
	return new Promise(function(resolve, reject) {
		_http(Object.assign({}, configuracion, {
			onSuccess: function(respuesta, xhr) {
				resolve({ datos: respuesta, xhr: xhr });
			},
			onError: function(error, xhr) {
				reject(error);
			}
		}));
	});
}

// Ejemplo de consumo asíncrono moderno
async function obtenerDatosDeUsuario() {
	try {
		var resultado = await solicitarRecurso({
			url: 'https://api.ejemplo.com/v1/perfil',
			method: 'GET'
		});
		console.log('Datos obtenidos:', JSON.parse(resultado.datos));
	}
	catch (error) {
		console.error('Error capturado con async/await:', error.message);
	}
}

6. Características Técnicas de la Implementación

Configuración Segura de Cabeceras: La aplicación de cabeceras HTTP personalizadas realiza una validación selectiva basada en hasOwnProperty sobre el mapa de propiedades proporcionado. Esto previene la inyección accidental de propiedades provenientes de la herencia del prototipo de los objetos de Javascript.


Gestión Ordenada de Excepciones de Tiempo de Espera: Al detectarse un evento de timeout nativo, el motor intenta delegar en primera instancia al controlador específico onTimeout. Si este no está presente, se genera automáticamente una instancia de Error detallada y se canaliza de forma segura al controlador general onError.


Transparencia de Datos en Envío: La propiedad de datos (data) es asignada de manera directa al método send() de XMLHttpRequest sin alteración de tipo previa, facilitando la integración con flujos de carga especializados y permitiendo la flexibilidad del navegador al determinar de forma automática cabeceras asociadas como el límite de frontera en estructuras multipart/form-data.