Cómo hacer solicitudes HTTP usando XMLHttpRequest (XHR)

XMLHttpRequest (XHR) fue inventado por Microsoft a principios de los años 90 y se convirtió en una tecnología de referencia para las interacciones asincrónicas del servidor a mediados de la primera década del siglo XXI.

Gracias a XHR, por primera vez fue posible actualizar partes de una página web sin recargar toda la página.

XMLHttpRequest es un objeto de navegador integrado en todos los navegadores modernos que se puede utilizar para realizar solicitudes HTTP en JavaScript para intercambiar datos entre el navegador web y el servidor.

A pesar de la palabra "XML" en su nombre, XMLHttpRequest se puede usar para recuperar cualquier tipo de datos y no solo XML. Podemos usarlo para cargar/descargar archivos, enviar datos de formularios, realizar un seguimiento del progreso y mucho más.

Solicitud básica de XHR

Para enviar una solicitud HTTP usando XHR, cree un XMLHttpRequest objeto, abra una conexión a la URL y envíe la solicitud. Una vez que se complete la solicitud, el objeto contendrá información útil, como el cuerpo de la respuesta y el código de estado HTTP.

Usemos la API REST de prueba JSONPlaceholder para enviar una solicitud GET usando XHR:

// create an XHR object
const xhr = new XMLHttpRequest();

// listen for `onload` event
xhr.onload = () => {
    // process response
    if (xhr.status == 200) {
        // parse JSON data
        console.log(JSON.parse(xhr.response));
    } else {
        console.error('Error!');
    }
};

// create a `GET` request
xhr.open('GET', 'https://jsonplaceholder.typicode.com/users');

// send request
xhr.send();

xhr.open() Método

En el ejemplo anterior, pasamos el método HTTP y una URL a la solicitud al open() método. Este método normalmente se llama justo después de new XMLHttpRequest() . Podemos usar este método para especificar los parámetros principales de la solicitud:

Esta es la sintaxis de este método:

xhr.open(method, URL, [async, user, password])
  • method — Método de solicitud HTTP. Puede ser GET , POST , DELETE , PUT , etc.
  • URL — La URL a solicitar, una cadena o un objeto de URL
  • asnyc — Especificar si la solicitud debe hacerse de forma asíncrona o no. El valor predeterminado es true
  • username &password — Credenciales para la autenticación HTTP básica

El open() El método no abre la conexión a la URL. Solo configura la solicitud HTTP.

xhr.send() Método

xhr.send([body])

El send() El método abre la conexión de red y envía la solicitud al servidor. Se necesita un body opcional parámetro que contiene el cuerpo de la solicitud. Para métodos de solicitud como GET no necesita pasar el parámetro del cuerpo.

Eventos XHR

Los tres eventos XHR más utilizados son los siguientes:

  • load — Este evento se llama cuando el resultado está listo. Es equivalente a xhr.onreadystatechange evento con xhr.readyState == 4 .
  • error — Este evento se activa cuando la solicitud falla debido a una caída de la red o una URL no válida.
  • progress — Este evento se activa periódicamente durante la descarga de la respuesta. Se puede usar para informar el progreso de solicitudes de red grandes.
// listen for `load` event
xhr.onload = () => {
    console.log(`Data Loaded: ${xhr.status} ${xhr.response}`);
};

// listen for `error` event
xhr.onerror = () => {
    console.error('Request failed.');
}

// listen for `progress` event
xhr.onprogress = (event) => {
    // event.loaded returns how many bytes are downloaded
    // event.total returns the total number of bytes
    // event.total is only available if server sends `Content-Length` header
    console.log(`Downloaded ${event.loaded} of ${event.total}`);
}

Tiempo de espera de solicitud

Puede configurar fácilmente el tiempo de espera de la solicitud especificando el tiempo en milisegundos:

// set timeout
xhr.timeout = 5000; // 5 seconds

// listen for `timeout` event
xhr.ontimeout = () => console.log('Request timeout.', xhr.responseURL);

Tipo de respuesta

Podemos usar xhr.responseType propiedad para establecer el formato de respuesta esperado:

  • Vacío (predeterminado) o text — texto sin formato
  • json — JSON analizado
  • blob — Blob de datos binarios
  • document — Documento XML
  • arraybufferArrayBuffer para datos binarios

Llamemos a una API RESTful para obtener la respuesta como JSON:

const xhr = new XMLHttpRequest();

xhr.open('GET', 'https://api.jsonbin.io/b/5d5076e01ec3937ed4d05eab/1');

// set response format
xhr.responseType = 'json';

xhr.send();

xhr.onload = () => {
    // get JSON response
    const user = xhr.response;

    // log details
    console.log(user.name); // John Doe
    console.log(user.email); // [email protected]
    console.log(user.website); // http://example.com
}

Estados de solicitud (xhr.readyState )

El XMLHttpRequest el objeto cambia de estado a medida que avanza la solicitud. Podemos acceder al estado actual usando xhr.readyState propiedad.

Los estados son:

  • UNSENT (0) — El estado inicial
  • OPENED (1) — Comienza la solicitud
  • HEADERS_RECEIVED (2) — Los encabezados HTTP recibidos
  • LOADING (3) — La respuesta se está cargando
  • DONE (4) — La solicitud está completa

Podemos rastrear el estado de la solicitud usando onreadystatechange evento:

xhr.onreadystatechange = function () {
    if(xhr.readyState == 1) {
        console.log('Request started.');
    }
    
    if(xhr.readyState == 2) {
        console.log('Headers received.');
    }
    
    if (xhr.readyState == 3) {
        console.log('Data loading..!');
    }
    if (xhr.readyState == 4) {
        console.log('Request ended.');
    }
};

Solicitud de cancelación

Podemos cancelar fácilmente una solicitud XHR en cualquier momento llamando al abort() método en el xhr objeto:

xhr.abort(); // cancel request

Solicitudes sincrónicas

De forma predeterminada, XHR realiza una solicitud asincrónica que es buena para el rendimiento. Pero si desea realizar una solicitud síncrona explícita, simplemente pase false como tercer argumento para open() método. Pausará la ejecución de JavaScript en send() y reanudar cuando la respuesta esté disponible:

xhr.open('GET', 'https://api.jsonbin.io/b/5d5076e01ec3937ed4d05eab/1', false);

Encabezados HTTP

XMLHttpRequest nos permite establecer encabezados de solicitud, así como encabezados de respuesta de lectura. Podemos configurar la solicitud Content-Type &Accept encabezados llamando a setRequestHeader() método en el xhr objeto:

// set request headers
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Accept', '*/*'); // accept all

Del mismo modo, si desea leer los encabezados de respuesta (excepto Set-Cookie ), llama al getResponseHeader() en el xhr objeto:

// read response headers
xhr.getResponseHeader('Content-Type');
xhr.getResponseHeader('Cache-Control');

¿Quiere obtener encabezados de respuesta a la vez? Utilice getAllResponseHeaders() en cambio:

xhr.getAllResponseHeaders();

Solicitud POST XHR

El XMLHttpRequest La solicitud POST para enviar los datos de un formulario se puede enviar de dos maneras:

  1. Usando solo Ajax
  2. Usando FormData API

El primer enfoque es lo suficientemente bueno a menos que desee cargar un archivo y necesite multipart/form-data codificación Así es como podemos hacer una solicitud POST con datos de formulario codificados en URL:

const xhr = new XMLHttpRequest();

// configure a `POST` request
xhr.open('POST', '/login');

// prepare form data
let params = 'username=attacomsian&password=123456';

// set `Content-Type` header
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

// pass `params` to `send()` method
xhr.send(params);

// listen for `load` event
xhr.onload = () => {
   console.log(xhr.responseText);
}

¿Quieres hacer una solicitud JSON POST? Asegúrese de convertir los datos JSON en una cadena usando JSON.stringify() y configure el Content-Type encabezado a application/json :

const xhr = new XMLHttpRequest();

// configure a `POST` request
xhr.open('POST', '/login');

// create a JSON object
const params = {
    username: 'attacomsian',
    password: '123456'
};

// set `Content-Type` header
xhr.setRequestHeader('Content-Type', 'application/json');

// pass `params` to `send()` method
xhr.send(JSON.stringify(params));

// listen for `load` event
xhr.onload = () => {
   console.log(xhr.responseText);
}

Solicitudes y cookies de origen cruzado

XMLHttpRequest puede enviar solicitudes de origen cruzado, pero está sujeto a medidas de seguridad especiales. Para solicitar un recurso de un servidor diferente, el servidor debe admitirlo explícitamente mediante CORS (intercambio de recursos de origen cruzado).

Al igual que Fetch API, XHR no envía cookies ni autorización HTTP a otro origen. Para enviar cookies, puede usar withCredentials propiedad del xhr objeto:

xhr.withCredentials = true;

XHR frente a jQuery

Métodos de contenedor de jQuery como $.ajax() utiliza XHR bajo el capó y proporciona un mayor nivel de abstracción para facilitar la vida de los desarrolladores. Usando jQuery, podemos traducir el código anterior en unas pocas líneas:

$.ajax('https://jsonplaceholder.typicode.com/users')
    .done(data => {
        console.log(data);
    }).fail(err => {
        console.error('Error:', err);
    });

XHR frente a la API de obtención

Fetch API es una alternativa moderna basada en promesas a XHR. Es limpio, más fácil de entender y se usa masivamente en los trabajadores de servicio de PWA.

El ejemplo anterior de XHR se puede convertir a un fetch() mucho más simple -código basado que incluso analiza automáticamente el JSON devuelto:

fetch('https://jsonplaceholder.typicode.com/users')
    .then(res => res.json())
    .then(json => console.log(json))
    .catch(err => console.error('Error:', err));

¿Quieres saber más? Consulte la guía de JavaScript Fetch API para comprender cómo puede usar Fetch API para solicitar recursos de red con solo unas pocas líneas de código.