AJAX cheat sheet

A scannable AJAX reference: 11 short snippets across 6 topics, each linking back to the lesson it came from.

At a glance

TopicWhat it covers
Requests with fetchIdempotency is what makes retries safe: repeating a PUT or DELETE leaves the same state, while repeating a POST usuallylesson
Bodies, headers and status codesSome headers can never be set from script: Host, Content-Length, Cookie and Origin belong to the browser. On the waylesson
XMLHttpRequest and the gaps in fetchThe original transport API, upload progress with xhr.upload, and an honest comparison of when XMLHttpRequest is stilllesson
Same-origin policy, CORS and credentialsAn origin is the scheme, host and port together. The policy does not stop a script from sending a cross-origin requestlesson
Caching and conditional requestsA validator lets the server answer a full request with 304 Not Modified and an empty body. You keep the parsing worklesson
Debugging network problemsThe console message names the cause once you read it as three parts: the request, the response headers, and the missinglesson

Quick snippets

Requests with fetch

A minimal request

const res = await fetch('/api/tasks?limit=20', {
  headers: { Accept: 'application/json' },
  credentials: 'same-origin'
});

if (!res.ok) throw new Error('HTTP ' + res.status);   // fetch does not throw on 404 or 500
const data = await res.json();                        // the body can be read once

Sending data

await fetch('/api/tasks', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ title: 'Ship it' })
});

const fd = new FormData(form);            // multipart; no header needed
await fetch('/upload', { method: 'POST', body: fd });

await fetch('/api/tasks/7', { method: 'DELETE' });

Full lesson: Requests with fetch →

Bodies, headers and status codes

Request and response headers

const res = await fetch('/api/me', {
  headers: {
    'Accept': 'application/json',
    'Authorization': 'Bearer ' + token,
    'X-CSRF-Token': getCsrfToken()
  }
});

res.headers.get('content-type');     // 'application/json; charset=utf-8'
res.headers.get('cache-control');
res.headers.get('link');             // pagination, when the API sends it

Reading the response body

const res = await fetch('/report.csv');

const text = await res.text();          // any text payload
const blob = await res.blob();          // binary; feed it to a download link
const buf  = await res.arrayBuffer();   // bytes for decoding yourself
const data = await res.json();          // JSON.parse on the body text

// stream a large body instead of buffering all of it
const reader = res.body.getReader();
const { value, done } = await reader.read();

Status codes worth branching on

async function request(url, init) {
  const res = await fetch(url, init);
  if (res.status === 204) return null;
  if (res.status === 401) { await refresh(); return request(url, init); }
  if (res.status === 429) {
    const wait = Number(res.headers.get('retry-after') || 5);
    throw new Error('rate limited, retry in ' + wait + 's');
  }
  if (!res.ok) throw new Error('HTTP ' + res.status);
  return res.json();
}

Full lesson: Bodies, headers and status codes →

XMLHttpRequest and the gaps in fetch

Upload progress

const xhr = new XMLHttpRequest();

xhr.upload.onprogress = event => {
  if (event.lengthComputable) {
    bar.value = Math.round((event.loaded / event.total) * 100);
  }
};
xhr.upload.onload = () => console.log('sent');
xhr.onload = () => console.log('response', xhr.status);

xhr.open('POST', '/upload');
xhr.send(file);

Choosing between them

// both transports cancel the same way from the caller's point of view
xhr.send();
xhr.abort();                     // fires onabort, then onloadend

const ac = new AbortController();
fetch(url, { signal: ac.signal }).catch(err => {
  if (err.name !== 'AbortError') throw err;
});
ac.abort();

Full lesson: XMLHttpRequest and the gaps in fetch →

Same-origin policy, CORS and credentials

What the same-origin policy really does

// same origin: CORS never enters the picture
await fetch('/api/me');

// cross-origin, credentials omitted by default
await fetch('https://api.example.com/me');

// cross-origin with cookies: the server must opt in too
await fetch('https://api.example.com/me', {
  credentials: 'include',
  headers: { 'X-Request-Id': crypto.randomUUID() }
});

Simple and preflighted requests

OPTIONS /me HTTP/1.1
Host: api.example.com
Origin: https://app.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: content-type, x-csrf-token

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, X-CSRF-Token
Access-Control-Max-Age: 600
Vary: Origin

Full lesson: Same-origin policy, CORS and credentials →

Caching and conditional requests

Cache-Control and freshness

// the browser handles freshness for you when the server allows it
const res = await fetch('/api/config');       // may come from the HTTP cache
res.headers.get('age');                      // seconds since the response was generated
res.headers.get('cache-control');

// bypass the cache deliberately: a pull-to-refresh, an after-write reload
await fetch('/api/tasks', { cache: 'no-store' });
await fetch('/api/tasks', { cache: 'reload' });

// force revalidation and accept a 304
await fetch('/api/tasks', { cache: 'no-cache' });

Full lesson: Caching and conditional requests →

Debugging network problems

Reading a CORS failure correctly

# reproduce without CORS: curl is not a browser and ignores the policy
curl -i -X OPTIONS 'https://api.example.com/me' \
  -H 'Origin: https://app.example.com' \
  -H 'Access-Control-Request-Method: PUT' \
  -H 'Access-Control-Request-Headers: content-type'

# if the headers are missing here, the problem is on the server, not in your code
curl -i 'https://api.example.com/me' -H 'Origin: https://app.example.com'

Full lesson: Debugging network problems →

FAQ

Is this AJAX cheat sheet free to use?
Yes. No sign-up and no tracking: the page is static, every example is on the page itself, and you can print it or save it as a one-page reference.
Where do the examples come from?
Every snippet is taken from the 6 lessons of the AJAX course on this site, and each section links back to the lesson it was pulled from.
How do I go deeper than a cheat sheet?
Open the full AJAX course — it carries the worked explanations, the edge cases and the exercises behind every line here.

HTML CSS JavaScript TypeScript HTML DOM JSON

Last refreshed 2026-09-27.