Start · Sprachen · JavaScript · Referenz · XMLHttpRequest.send()

XMLHttpRequest.send()

Methode

Sendet die zuvor mit <code>open()</code> vorbereitete HTTP-Anfrage an den Server, optional mit einem Anfragekörper.

seit JavaScript Baseline: alle Browser Kategorie: webapi

Signatur

XMLHttpRequest.prototype.send(body)

Beschreibung

send() ist der letzte Schritt einer XMLHttpRequest-Anfrage: Nachdem mit open() Methode und URL festgelegt und gegebenenfalls mit setRequestHeader() Header gesetzt wurden, schickt send() die Anfrage tatsächlich ab. Bei asynchronen Anfragen (Standard) kehrt die Methode sofort zurück. Das Ergebnis erhältst du über Events wie load, error, progress oder readystatechange.

Über den optionalen Parameter body übergibst du Daten, etwa bei POST oder PUT. Erlaubt sind unter anderem Zeichenketten (z. B. JSON), FormData, URLSearchParams, Blob/File, ArrayBuffer, typisierte Arrays und Document. Je nach Typ setzt der Browser automatisch einen passenden Content-Type, z. B. multipart/form-data mit Boundary bei FormData.

Bei GET- und HEAD-Anfragen wird ein übergebener Body ignoriert und als null behandelt. In neuem Code ist meist fetch() die bessere Wahl. XMLHttpRequest ist aber weiterhin sinnvoll, wenn du den Upload-Fortschritt über xhr.upload.onprogress brauchst. Das kann fetch() bis heute nicht einfach.

Parameter

Name Typ Default Beschreibung
$body string | Document | Blob | ArrayBuffer | ArrayBufferView | FormData | URLSearchParams | ReadableStream | null null Der Anfragekörper. Wird bei GET und HEAD ignoriert. Ohne Angabe oder bei null wird kein Body gesendet.

Rückgabewert

Typ
void
Beschreibung
Gibt undefined zurück. Die Antwort steht nach Abschluss in xhr.response, xhr.responseText und xhr.status bereit.

Beispiele

Einfache GET-Anfrage mit JSON-Antwort

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

xhr.addEventListener('load', () => {
  if (xhr.status >= 200 && xhr.status < 300) {
    console.log('Titel:', xhr.response.title);
  } else {
    console.error('HTTP-Fehler:', xhr.status);
  }
});
xhr.addEventListener('error', () => console.error('Netzwerkfehler'));

xhr.send(); // kein Body bei GET
Titel: delectus aut autem

JSON per POST senden

const neuerEintrag = { title: 'Einkaufen', completed: false, userId: 1 };

const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://jsonplaceholder.typicode.com/todos');
xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
xhr.responseType = 'json';

xhr.onload = () => {
  console.log(xhr.status, xhr.response);
};

xhr.send(JSON.stringify(neuerEintrag));
201 { title: 'Einkaufen', completed: false, userId: 1, id: 201 }

Datei-Upload mit Fortschrittsanzeige (FormData)

const input = document.querySelector('#datei');
const balken = document.querySelector('progress');

input.addEventListener('change', () => {
  const formData = new FormData();
  formData.append('datei', input.files[0]);

  const xhr = new XMLHttpRequest();
  xhr.open('POST', '/api/upload');

  // Upload-Fortschritt – mit fetch() nicht direkt möglich
  xhr.upload.onprogress = (e) => {
    if (e.lengthComputable) {
      balken.value = Math.round((e.loaded / e.total) * 100);
    }
  };
  xhr.onload = () => console.log('Upload fertig:', xhr.status);

  // Content-Type NICHT manuell setzen – der Browser ergänzt die Boundary
  xhr.send(formData);
});
Upload fertig: 200

send() in ein Promise verpacken

const request = (method, url, body = null) =>
  new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open(method, url);
    xhr.responseType = 'json';
    xhr.timeout = 5000;
    xhr.onload = () =>
      xhr.status < 400 ? resolve(xhr.response) : reject(new Error(`HTTP ${xhr.status}`));
    xhr.onerror = () => reject(new Error('Netzwerkfehler'));
    xhr.ontimeout = () => reject(new Error('Zeitüberschreitung'));
    xhr.send(body);
  });

const main = async () => {
  const user = await request('GET', 'https://jsonplaceholder.typicode.com/users/1');
  console.log(user.name);
};
main();
Leanne Graham

// Wichtig · Fallstricke

  • Reihenfolge: send() darf erst nach open() aufgerufen werden. Sonst wirft es eine InvalidStateError-DOMException. Ein zweiter send()-Aufruf auf dieselbe Anfrage ohne erneutes open() führt ebenfalls zu diesem Fehler.
  • HTTP-Fehler sind keine Netzwerkfehler: Auch bei 404 oder 500 wird load ausgelöst. Prüfe deshalb immer xhr.status. error tritt nur bei Netzwerk- oder CORS-Problemen auf.
  • Synchrone Anfragen (open(method, url, false)) blockieren den Haupt-Thread. Im Hauptkontext gelten sie als veraltet und erzeugen Konsolenwarnungen. timeout und responseType sind dort nicht nutzbar.
  • FormData: Setze keinen eigenen Content-Type-Header, sonst fehlt die Multipart-Boundary und der Server kann den Body nicht auswerten.
  • CORS: Anfragen an fremde Origins unterliegen der Same-Origin-Policy. Eigene Header oder ein Content-Type: application/json lösen eine Preflight-Anfrage (OPTIONS) aus. Cookies werden nur mit xhr.withCredentials = true mitgesendet.
  • Kompatibilität: Wird von allen Browsern unterstützt. ReadableStream als Body wird praktisch nicht unterstützt. In Service Workern gibt es kein XMLHttpRequest, dort nutzt du fetch().