Konrad Kowalski (rootsher)Principal Platform & Reliability Architect101100000010101011111001001010110100010111000100

Headers i Body: metadane kontra reprezentacja

data
kategoria
Frontend
także w
Backend
czytanie
1 min / 207 słów

Typowy request:

js
fetch("/api/users", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    name: "Alice"
  })
});

Łatwo potraktować Content-Type jak boilerplate.

Nie jest nim.

Body to bytes, nie JSON

Dla HTTP body jest contentem przesyłanym jako sekwencja bajtów.

To header mówi odbiorcy, jak je interpretować:

http
Content-Type: application/json

Inne możliwości:

text
text/plain
text/html
application/octet-stream
multipart/form-data
image/webp

HTTP nie wymaga JSON-a.

JSON jest wyborem warstwy aplikacyjnej.

Content-Type opisuje to, co wysyłamy

http
Content-Type: application/json

oznacza:

content tej wiadomości jest JSON-em.

Natomiast:

http
Accept: application/json

oznacza:

klient preferuje JSON jako reprezentację response.

To dwa różne kierunki negocjacji.

text
Content-Type -> what I am sending
Accept       -> what I want back

Browser potrafi zbudować body za nas

Dla FormData:

js
const form = new FormData();

form.append("name", "Alice");
form.append("avatar", file);

fetch("/profile", {
  method: "POST",
  body: form
});

Nie powinniśmy ręcznie ustawiać:

http
Content-Type: multipart/form-data

Browser musi dodać poprawny boundary.

Przykładowo:

text
multipart/form-data; boundary=----browser-generated

To przykład sytuacji, w której ręczna kontrola nad HTTP pogarsza request.

Content-Encoding jest inną warstwą

Response może mieć:

http
Content-Type: application/json
Content-Encoding: gzip

Semantycznie reprezentacja jest JSON-em.

Na wire content został dodatkowo zakodowany kompresją.

Browser zwykle dekompresuje go przed udostępnieniem przez Fetch API.

Frontend dostaje:

js
await response.json();

a nie skompresowane bajty gzip do ręcznego rozpakowania.

Content-Length nie zawsze jest potrzebny

Jeżeli rozmiar content jest znany, może pojawić się:

http
Content-Length: 842

Ale streaming response może być produkowany stopniowo.

Wtedy pełny rozmiar nie musi być znany na początku.

To ważne dla frontendu:

text
response headers available
!=
entire body downloaded

Dlatego Response.body może być ReadableStream.

Headers sterują zachowaniem browsera

Headers nie są tylko metadata dla backendu.

Mogą wpływać na:

text
cache
cookies
content interpretation
redirects
CORS
download behavior
security policy

Ale JavaScript nie ma nad nimi pełnej kontroli.

Browser jest aktywnym uczestnikiem HTTP i część requestu buduje sam.

To będzie tematem następnego artykułu.