Warum große Ganzzahlen Präzision verlieren
Fazit: Ganzzahlen oberhalb von 2^53-1 verlieren in JSON.parse Präzision. Snowflake-IDs, Bestellnummern und Datenbank-Bigints sind alle betroffen, halten Sie sie also durchgängig als Strings.

Kurz gesagt: Behandeln Sie Snowflake-IDs, Bestellnummern und Bigint-Primärschlüssel als Strings durch Serialisierung, Transport und Parsen; behalten Sie den numerischen Typ nur, wenn nachweislich feststeht, dass das Feld innerhalb von 2^53-1 bleibt, und erzwingen Sie es dann mit einer maximum-Beschränkung im Schema.
Weil der Schaden beim Parsen entsteht, stillschweigend.
JSON.parse('{"id": 9007199254740993}');
// { id: 9007199254740992 }
Die fehlende Ziffer ist weg; es gibt nichts wiederherzustellen.
Woher 2^53 kommt
JavaScript hat einen numerischen Typ: IEEE 754 doppelte Präzision, mit 53 Bits Signifikand (eins implizit, 52 explizit). Exakte Ganzzahlen enden also bei ±(2^53-1):
-9007199254740991 .. 9007199254740991
Über dieser Linie liegen aufeinanderfolgende darstellbare Werte 2, 4, 8 auseinander. 9007199254740993 ist ungerade, und in dieser Größenordnung ist jeder darstellbare Wert gerade, es rundet also auf 9007199254740992.
Welche Felder getroffen werden
| Feld | Ziffern | Risiko |
|---|---|---|
| Snowflake-IDs | 18–19 | Hoch, letzte Ziffern ändern sich |
| Bestell-/Transaktionsnummern | 16–20 | Hoch |
| Datenbank-Bigint-Primärschlüssel | 19 | Hoch |
| Geld in kleinster Einheit | — | Niedrig |
| Millisekunden-Timestamps | 13 | Sicher |
Der gemeinsame Faden: Das sind Kennungen, keine Mengen. Eine Kennung wird transportiert, nie addiert oder multipliziert, String ist also der richtige Typ.
Vier Behebungen
Als String serialisieren. Das Backend konvertiert Bigint-Felder, bevor es die Antwort schreibt. Einfach und dauerhaft; dokumentieren Sie, dass diese Felder Strings sind.
Den Serializer es erledigen lassen. Jacksons ToStringSerializer für Long, Gos json:",string"-Tag. Dieselbe Idee: den Wert aus dem numerischen Pfad heraushalten.
Mit BigInt-Unterstützung parsen. json-bigint und ähnliche Bibliotheken. Beachten Sie, dass BigInt nicht mit Number-Arithmetik gemischt werden kann und JSON.stringify es ablehnt.
Den Bereich beschränken. Kann das Feld wirklich nicht 2^53 überschreiten, ergänzen Sie maximum im Schema, damit Daten außerhalb des Bereichs die Validierung nicht bestehen, statt im Browser stillschweigend zu scheitern.
Wie man erkennt, ob man diesen Bug hat
Nehmen Sie eine bekannte ID und führen Sie sie im Roundtrip: serialisieren, übertragen, parsen, Zeichen für Zeichen vergleichen. Oder prüfen Sie den rohen Response-Body – eine unquotierte 19-stellige Zahl, die mit falschen Endziffern ankommt, ist fast sicher ein Verlust zur Parse-Zeit.
FAQ
Warum ändert JSON.parse die letzten Ziffern ohne Fehler?
JavaScript hat einen numerischen Typ, IEEE 754 doppelte Präzision, Ganzzahlen über 2^53-1 können also nur auf dem nächstgelegenen darstellbaren Wert landen. JSON.parse behandelt das als normale numerische Konvertierung: Es wirft nicht und warnt nicht.
Wie kann das Frontend große Ganzzahlen intakt halten?
Verwenden Sie eine Bibliothek wie json-bigint, weil JSON.parse es nicht kann. Der Preis ist, dass BigInt nicht mit Number-Arithmetik gemischt werden kann und JSON.stringify es ablehnt, der umgebende Code muss sich also ebenfalls ändern.
Sollten die API-Dokumente festhalten, dass diese Felder Strings sind?
Ja. Die Serialisierung zu Strings ist die einfachste und dauerhafteste Behebung, aber sie funktioniert nur, wenn Konsumenten den Wert als Text behandeln, der Feldtyp muss also in den API-Vertrag geschrieben werden.