Konrad Kowalski (rootsher)Principal Platform & Reliability Architect011011111001010101110111110000010100110010000111

Request i Response: co faktycznie wysyła browser?

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

Frontend pisze:

js
await fetch("/api/users/42");

Na poziomie HTTP intencja wygląda mniej więcej tak:

http
GET /api/users/42

Ale request to nie URL.

Semantycznie składa się z:

text
method
target
headers
optional content

Response analogicznie:

text
status
headers
optional content

Request

Przykład uproszczony do HTTP/1.1 notation:

http
GET /api/users/42 HTTP/1.1
Host: example.com
Accept: */*
Cookie: session=...

Browser może dodać część headers sam.

JavaScript nie konstruuje surowego pakietu sieciowego.

Wywołuje browser API:

text
JavaScript
   |
   v
Fetch
   |
   v
browser builds HTTP request

To rozróżnienie będzie wracało przez całą serię.

Response

Backend może odpowiedzieć:

http
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 24

{"id":42,"name":"Alice"}

W fetch() najpierw dostajemy obiekt Response:

js
const response = await fetch(url);

response.status;
response.headers;

A body konsumujemy osobno:

js
const user = await response.json();

To nie jest przypadek.

Headers i body mają osobny lifecycle.

fetch() resolve nie oznacza 200

Jeżeli backend odpowie:

http
HTTP/1.1 404 Not Found

browser dostał poprawną odpowiedź HTTP.

Dlatego:

js
const response = await fetch("/missing");

console.log(response.status); // 404
console.log(response.ok);     // false

Promise nie musi zostać odrzucony.

Dla Fetch API:

text
HTTP error response
!=
network failure

To bardzo ważna granica.

404 i 500 są informacją wewnątrz HTTP.

Brak możliwej do udostępnienia odpowiedzi jest inną klasą problemu.

Body nie zawsze istnieje

Frontend często zakłada:

text
response = JSON

Ale HTTP response może nie mieć content.

Przykład:

http
HTTP/1.1 204 No Content

Kod:

js
await response.json();

nie ma wtedy czego parsować.

API client powinien więc rozumieć kontrakt endpointu, a nie automatycznie traktować każdy sukces jako JSON.

HTTP message to abstrakcja

W HTTP/1.1 request wygląda na wire mniej więcej jak tekst, który pokazaliśmy.

W HTTP/2 request jest zakodowany jako binary frames.

W HTTP/3 również nie jest wysyłany jako tekstowa linia:

text
GET /api/users/42 HTTP/1.1

Mimo to semantycznie nadal jest:

text
GET
/api/users/42
headers

Dlatego DevTools pokazuje nam logiczny HTTP request, niekoniecznie bajty lecące po sieci.

To prowadzi do następnego pytania.

Skoro GET, POST, 404 i 500 są częścią semantyki HTTP, to co dokładnie znaczą i dlaczego browser oraz infrastruktura mogą zachowywać się inaczej zależnie od metody i statusu?