Egy lassú oldalnál a böngésző hálózati vízesése gyakran csak annyit mond: a kérés 430 ms-ig „várt”. Ebből nem derül ki, hogy a CDN cache-t keresett, az alkalmazás renderelt, vagy az adatbázis akadt meg. A Server-Timing HTTP válaszfejléc erre való: a szerver rövid, strukturált időmérőket küld a válasszal, amelyeket a böngésző a saját hálózati adatai mellé tesz.

Nem ugyanaz, mint a hálózati idő
A DevTools Network panelje a kliens szemszögéből mér: DNS, kapcsolat, kérésküldés, TTFB, letöltés. A TTFB végén viszont sok minden összemosódik: proxyzás, cache-olvasás, alkalmazáskód, külső API és adatbázis. A Server-Timing ezeket a szerver által ismert szakaszokat adja hozzá. Egy válasz például ezt küldheti:
Server-Timing: cdn;desc=HIT, db;dur=18.4, render;dur=6.2, app;dur=27.1
A metrika neve kötelező token, a dur és a desc opcionális. A specifikáció szerint ugyanaz a név többször is előfordulhat, ezért egy terheléselosztó, CDN és origin is hozzáadhat saját mérést. A paraméterek sorrendje nem jelent semmit, és a böngészőnek sem kell a fejlécbeli sorrendben megjelenítenie őket. Ne próbáld tehát a nevekből vagy a listabeli pozícióból visszaépíteni az útvonalat.
Kis mérőkeret egy Node szerverben
Node-ban nincs hozzá külön csomag: a response.setHeader() bármely válaszfejlécet beállít. A példa egy valós adatbázis- és SSR-részlet helyett rövid várakozásokkal modellezi a szakaszokat; a mérőkeret maga változtatás nélkül használható middleware-ben vagy route handlerben.
import { createServer } from "node:http";
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
async function timed(metrics, name, operation) {
const started = performance.now();
const value = await operation();
metrics.push({ name, duration: performance.now() - started });
return value;
}
createServer(async (_request, response) => {
const started = performance.now();
const metrics = [];
const user = await timed(metrics, "db", async () => {
await wait(18); // Valódi adatbázis-hívás helye
return { name: "Ada" };
});
const body = await timed(metrics, "render", async () => {
await wait(4); // Template vagy SSR
return `<h1>Szia, ${user.name}!</h1>`;
});
metrics.push({ name: "app", duration: performance.now() - started });
response.setHeader("Server-Timing", metrics
.map(({ name, duration }) => `${name};dur=${duration.toFixed(1)}`)
.join(", "));
response.setHeader("Content-Type", "text/html; charset=utf-8");
response.end(body);
}).listen(3001);
Éles kódban ne az egyes SQL-sorokat vedd fel metrikának. Legyen kevés, stabil nevű szakasz: például cache, db, upstream, render és app. Egy névhez rövid leírás még belefér, de a fejléc minden válasszal utazik; a specifikáció is rövid neveket és leírásokat javasol a HTTP-többlet csökkentésére.
A böngészőben és JavaScriptből
A böngésző a DevToolsban is megjelenítheti az ilyen szerveroldali mérőket. Programból a PerformanceResourceTiming.serverTiming tömbben érhetők el: minden elemnek name, duration és description tulajdonsága van. Ez akkor hasznos, ha a saját RUM beaconödbe a kliens LCP-je mellé szeretnéd elküldeni, hogy az adott válasznál mennyi volt például a backend ideje.
Itt jön a fontos korlát: a szerver időmérője infrastruktúra-információ lehet. Más originről a böngésző alapból nem teszi olvashatóvá a serverTiming adatot. A forrásnak ehhez explicit Timing-Allow-Origin fejlécet kell küldenie, például Timing-Allow-Origin: https://app.example. Nyilvános végponton különösen ne küldj shard-nevet, belső régióazonosítót vagy olyan részletes metrikát, amelyből a rendszered felépítése következtethető ki.
Mire jó hibakereséskor?
A Server-Timing nem APM-helyettesítő és nem elosztott trace: nincs közös órája a klienssel, ezért a metrikákhoz szándékosan nem tartozik kliensoldali startTime. Viszont kiváló korrelációs jel. Ha a felhasználó lassú TTFB-t lát, egy cdn;desc=MISS és upstream;dur=240 pár rögtön más hibakeresési irányba visz, mint egy 4 ms-os app érték. A CDN vagy proxy saját metrikát is adhat hozzá, így ugyanabban a válaszban elfér a cache-döntés és az origin mérése.
Egyetlen kérés teljes ideje nem a metrikák összege: a szakaszok egymásba ágyazódhatnak, párhuzamosan futhatnak, és a proxy ideje is rájöhet. Ezért a db és az app értékét inkább együtt olvasd: az előbbi egy részletet, az utóbbi az alkalmazás által mért teljes keretet jelöli. A cél nem a tökéletes idővonal, hanem a gyors szűkítés.
Érdemes először csak a belső vagy autentikált HTML-válaszokon bekapcsolni, három-négy metrikával. A következő incidensnél a frontend, a backend és az üzemeltetés ugyanazt a kérést látja majd, nem három egymásnak ellentmondó idősorát.