W3docs

XMLHttpRequest

Aprenda a usar XMLHttpRequest (XHR) em JavaScript para enviar requisições HTTP assíncronas: métodos open e send, readyState, eventos load/error/timeout, análise de JSON, envio de dados com POST e cancelamento de requisições.

JavaScript é uma linguagem de programação essencial para o desenvolvimento web, possibilitando experiências dinâmicas e interativas para o usuário. Um dos principais recursos do JavaScript é a sua capacidade de se comunicar com servidores, recuperar dados e atualizar páginas web de forma assíncrona. Isso é obtido principalmente por meio do XMLHttpRequest (XHR). Este artigo oferece uma análise aprofundada do XMLHttpRequest, incluindo seus métodos, propriedades e aplicações práticas, com diversos exemplos de código para facilitar o aprendizado.

Informação

XMLHttpRequest trabalha com funções de callback. Para novos códigos, você geralmente preferirá a Fetch API, que é baseada em promessas e funciona perfeitamente com async/await. Ainda vale a pena entender o XHR: você o encontrará em bases de código mais antigas, e ele continua sendo a única API nativa que reporta o progresso de upload com granularidade.

Esta página aborda o que é um objeto XHR, como configurar e enviar uma requisição com open e send, como ler a resposta por meio de readyState e dos eventos load/error/timeout, como analisar JSON, como fazer POST de dados, como cancelar uma requisição e como o XHR se compara ao fetch.

Entendendo o XMLHttpRequest

XMLHttpRequest (XHR) é um objeto nativo do navegador que permite ao JavaScript enviar uma requisição HTTP ou HTTPS para um servidor e receber a resposta sem recarregar a página. O "XML" no nome é histórico — o XHR pode transferir qualquer formato de texto ou binário, sendo o JSON de longe o mais comum hoje em dia. Essa capacidade de se comunicar com um servidor em segundo plano é a base do que costumava ser chamado de AJAX (Asynchronous JavaScript and XML).

O ciclo de vida de uma requisição é sempre o mesmo: criar o objeto, abrir (configurar método e URL), anexar manipuladores de eventos para reagir ao resultado e, em seguida, enviar.

Criando um Objeto XMLHttpRequest

Primeiro, crie uma instância:

const xhr = new XMLHttpRequest();

Uma única instância de XMLHttpRequest trata de uma requisição. Para fazer uma segunda requisição, crie um novo objeto.

Fazendo uma Requisição HTTP

Assim que o objeto existir, configure-o com open e, em seguida, dispare-o com send.

O Método open

open inicializa uma requisição, mas não a envia ainda. Ele recebe vários parâmetros:

xhr.open(method, url, async, user, password);
  • method: O método HTTP a ser usado, por exemplo, 'GET' ou 'POST'.
  • url: A URL para a qual a requisição é enviada.
  • async: Um boolean que indica se a requisição é assíncrona. O padrão é true, e você quase sempre deve deixá-lo assim (veja o aviso abaixo).
  • user: Nome de usuário opcional para autenticação HTTP.
  • password: Senha opcional para autenticação HTTP.

Exemplo:

xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
Aviso

Requisições síncronas (xhr.open(method, url, false)) bloqueiam a página até a resposta chegar e estão depreciadas na thread principal. Mantenha sempre async definido como true.

O Método send

send despacha a requisição para o servidor. Todos os manipuladores de eventos devem ser anexados antes de chamá-lo. Para uma requisição GET, chame-o sem argumentos. Para um POST, passe o corpo da requisição como argumento.

Exemplo de uma requisição GET:

xhr.send();

Exemplo de uma requisição POST com dados codificados como formulário:

xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('param1=value1&param2=value2');

O método setRequestHeader adiciona um cabeçalho HTTP à requisição de saída e deve ser chamado após open, mas antes de send.

Tratando Respostas do Servidor

Para tratar respostas do servidor, vários listeners de eventos podem ser usados.

O Evento onreadystatechange

O evento onreadystatechange é disparado sempre que a propriedade readyState muda. A propriedade readyState contém o status do XMLHttpRequest.

  • 0: UNSENT
  • 1: OPENED
  • 2: HEADERS_RECEIVED
  • 3: LOADING
  • 4: DONE

Uma requisição só está concluída e bem-sucedida quando readyState é 4 (DONE) e o status HTTP está na faixa de sucesso (tipicamente 200). Verificar apenas readyState === 4 é um erro comum, pois o servidor pode ter respondido com 404 ou 500.

Exemplo:

javascript— editable
Nota

Embora onreadystatechange funcione, o código moderno geralmente prefere onload e onerror para um tratamento de requisições mais simples e legível. onreadystatechange é usado principalmente quando você precisa rastrear estados intermediários (como progresso ou cabeçalhos recebidos).

O Evento load

O evento load é disparado assim que a resposta chega completamente. É mais simples que onreadystatechange, pois você não precisa testar readyState — ele só é disparado no estágio DONE. Você ainda verifica status para distinguir um sucesso real de um erro HTTP.

Exemplo:

javascript— editable

O Evento progress

Para downloads grandes, você pode reportar o progresso com o evento progress. Quando o servidor envia um cabeçalho Content-Length, o evento é determinado (lengthComputable é true) e você pode calcular uma porcentagem:

xhr.onprogress = function(event) {
  if (event.lengthComputable) {
    const percent = Math.round((event.loaded / event.total) * 100);
    console.log(`Downloaded ${percent}%`);
  }
};

Para rastrear um upload, em vez disso, anexe manipuladores a xhr.upload (xhr.upload.onprogress). O objeto de progresso de upload é o recurso que o Fetch ainda não consegue replicar completamente.

Tratando Erros

Um código robusto deve tratar falhas. Dois eventos cobrem os casos de falha:

  • onerror é disparado em uma falha no nível de rede — a requisição nunca chegou ao servidor, o DNS falhou, o CORS a bloqueou, etc. Note que um HTTP 404 ou 500 não é um erro de rede: ele dispara load, não error, portanto você ainda deve inspecionar status.
  • ontimeout é disparado se a requisição demorar mais do que xhr.timeout milissegundos. Um timeout de 0 (o padrão) significa sem limite.

Exemplo:

javascript— editable

Analisando Respostas JSON

As respostas do servidor são mais comumente JSON. A abordagem mais simples é ler o texto bruto de xhr.responseText e analisá-lo você mesmo com JSON.parse:

javascript— editable

Alternativamente, defina xhr.responseType = 'json' antes de enviar, e o navegador analisará o corpo por você. O valor analisado estará disponível em xhr.response (não em xhr.responseText):

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
xhr.responseType = 'json';

xhr.onload = function() {
  if (xhr.status === 200) {
    console.log('title: ' + xhr.response.title); // already an object
  }
};

xhr.send();

responseType também aceita 'text', 'blob', 'arraybuffer' e 'document' para cargas úteis não JSON.

Enviando Dados com POST

Para enviar um corpo JSON, defina o cabeçalho Content-Type e serialize seu objeto com JSON.stringify:

const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://jsonplaceholder.typicode.com/posts', true);
xhr.setRequestHeader('Content-Type', 'application/json');

xhr.onload = function() {
  if (xhr.status === 201) { // 201 Created
    console.log('Created:', xhr.responseText);
  }
};

xhr.send(JSON.stringify({ title: 'foo', body: 'bar', userId: 1 }));

Para envios de formulários tradicionais, envie um objeto FormData em vez disso — o navegador define o Content-Type multipart correto automaticamente, portanto não chame setRequestHeader para isso.

Cancelando uma Requisição

Chame xhr.abort() para cancelar uma requisição em andamento, por exemplo, quando o usuário navega para outra página ou digita uma nova consulta de pesquisa. Após o cancelamento, o evento abort é disparado em vez de load:

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts', true);
xhr.onabort = () => console.log('Request was cancelled');
xhr.send();

// Later, cancel it:
xhr.abort();

O equivalente no Fetch usa um AbortController.

XMLHttpRequest vs Fetch

XMLHttpRequestFetch
Modelo de programaçãoCallbacks / eventosPromessas, funciona com await
Progresso de uploadSim (xhr.upload)Não
Progresso de downloadSim (evento progress)Via streams (mais código)
Cancelamentoxhr.abort()AbortController
Rejeita em erro HTTPNão, você verifica statusNão, você verifica response.ok

Para a maioria dos novos códigos, prefira o Fetch. Recorra ao XHR quando precisar de relatórios granulares de progresso de upload ou quando for necessário suportar ambientes muito antigos.

Conclusão

XMLHttpRequest permite que o JavaScript troque dados com um servidor em segundo plano: você cria o objeto, abre-o com open, anexa manipuladores load/error/timeout e o envia com send. Lembre-se de verificar tanto readyState quanto status, analisar JSON você mesmo ou por meio de responseType, e usar abort() para cancelar requisições desatualizadas. Para a maioria dos novos códigos, a Fetch API baseada em promessas é o melhor padrão, mas entender o XHR mantém você fluente em bases de código mais antigas e nos casos — como o progresso de upload — em que ele ainda se sobressai.

Prática

Prática
Quais das seguintes afirmações sobre XMLHttpRequest estão corretas?
Quais das seguintes afirmações sobre XMLHttpRequest estão corretas?
Was this page helpful?