JSON Toolkit

لماذا تفقد الأعداد الصحيحة الكبيرة دقتها

الخلاصة: الأعداد الصحيحة فوق 2^53-1 تفقد دقتها في JSON.parse. معرّفات snowflake وأرقام الطلبات وbigints قواعد البيانات كلها تصطدم بذلك، فاحفظها كنصوص من الطرف إلى الطرف.

متوسطقراءة نحو 4 دقيقةنُشر في 2026-10-30حُدِّث في 2026-11-04
لماذا تفقد الأعداد الصحيحة الكبيرة دقتها في JSON وكيف تحفظها

الخلاصة: عامل معرّفات snowflake وأرقام الطلبات ومفاتيح bigint الأساسية كنصوص عبر التسلسل والنقل والتحليل؛ واحتفظ بالنوع الرقمي فقط عندما يثبت أن الحقل يبقى داخل 2^53-1، ثم افرضه بقيد maximum في Schema.

لأن الضرر يحدث أثناء التحليل، بصمت.

JSON.parse('{"id": 9007199254740993}');
// { id: 9007199254740992 }

الرقم المفقود ذهب؛ ولا شيء لاستعادته.

من أين يأتي 2^53

لـJavaScript نوع عددي واحد: الدقة المزدوجة IEEE 754، بـ53 بت في الجزء المعنوي (واحد ضمني و52 صريح). لذا تتوقف الأعداد الصحيحة الدقيقة عند ±(2^53-1):

-9007199254740991 .. 9007199254740991

فوق ذلك الحد، تكون القيم الممثلة المتتالية متباعدة بمقدار 2 و4 و8. و9007199254740993 عدد فردي، وعند ذلك المقدار تكون كل قيمة ممثلة زوجية، فيُقرَّب إلى 9007199254740992.

الحقول التي تُصاب

الحقل الأرقام الخطر
معرّفات snowflake 18–19 مرتفع، والأرقام الأخيرة تتغير
أرقام الطلبات / المعاملات 16–20 مرتفع
مفاتيح bigint الأساسية في قواعد البيانات 19 مرتفع
المال بالوحدات الصغيرة — منخفض
الطوابع الزمنية بالمللي ثانية 13 آمن

الخيط المشترك: هذه معرّفات، لا كميات. المعرّف يُنقل ولا يُجمع ولا يُضرب، فالسلسلة النصية هي النوع الصحيح.

أربعة إصلاحات

سلسل كنص. يحوّل الخادم حقول bigint قبل كتابة الرد. بسيط ومتين؛ ووثّق أن هذه الحقول نصوص.

دع المسلسل يتعامل معه. ToStringSerializer في Jackson لـLong، ووسم json:",string" في Go. الفكرة نفسها: أبقِ القيمة خارج المسار الرقمي.

حلّل مع دعم BigInt. json-bigint ومكتبات مشابهة. لاحظ أن BigInt لا يختلط بحساب Number، وJSON.stringify يرفضه.

قيّد النطاق. إن كان الحقل فعلًا لا يتجاوز 2^53، فأضف maximum في Schema حتى تفشل البيانات خارج النطاق في التحقق بدلًا من الفشل الصامت في المتصفح.

كيف تعرف هل لديك هذا العيب

خذ معرّفًا معروفًا ومرّره ذهابًا وإيابًا: سلسل، وانقل، وحلّل، وقارن حرفًا بحرف. أو افحص جسم الرد الخام — عدد من 19 رقمًا بلا اقتباسات يصل بأرقام أخيرة خاطئة هو على الأرجح فقدان أثناء التحليل.

الأسئلة الشائعة

لماذا يغيّر JSON.parse الأرقام الأخيرة دون خطأ؟

لـJavaScript نوع عددي واحد، الدقة المزدوجة IEEE 754، لذا يمكن للأعداد الصحيحة فوق 2^53-1 أن تهبط فقط على أقرب قيمة ممثلة. ويعامل JSON.parse ذلك كتحويل عددي عادي: لا يرمي ولا يحذّر.

كيف يمكن للواجهة الحفاظ على الأعداد الصحيحة الكبيرة سليمة؟

استخدم مكتبة مثل json-bigint، لأن JSON.parse لا يستطيع ذلك. الكلفة أن BigInt لا يختلط بحساب Number وأن JSON.stringify يرفضه، فيجب أن يتغير الكود المحيط أيضًا.

هل يجب أن تنص وثائق API على أن هذه الحقول نصوص؟

نعم. التسلسل إلى نصوص هو الإصلاح الأبسط والأكثر متانة، لكنه لا يعمل إلا إذا عامل المستهلكون القيمة كنص، فيجب كتابة نوع الحقل في عقد API.

قراءة إضافية