У длинного ID в JSON меняются последние цифры: где потеря
Если у длинного ID в JSON меняются последние цифры, сравните исходный ответ с результатом разбора: JavaScript Number может не сохранить такое целое точно. Для идентификатора обычно нужен согласованный строковый контракт на всём пути. Преобразование уже изменённого числа в строку не восстановит исходные цифры, если первоначальное представление больше не сохранено.
Сначала отличите повреждение от сокращения на экране
Показанный номер может быть визуально сокращён, выведен в экспоненциальной форме или действительно изменён. Проверьте значение и тип в конкретной точке процесса, не делая вывод по одной ячейке таблицы. В диагностике используйте вымышленный идентификатор: реальные номера клиентов и действующие запросы для этого не нужны.
Проследите исходный текст ответа, результат парсера, состояние формы и обратное сохранение. Если в первом тексте цифры ещё верны, а сразу после разбора уже отличаются, оформление таблицы не является первым местом потери. Если проблема появилась раньше, разбирать нужно и серверное представление. У веб-приложения это один сквозной контракт, а не отдельная настройка поля.
Граница безопасного целого не равна границе любого числа
По MDN Number.MAX_SAFE_INTEGER максимальное безопасное целое равно 9007199254740991, то есть 2^53−1. Речь о точном представлении и сравнении целых в безопасной области. Это не максимальное конечное значение Number и не утверждение, что каждое большее число обязательно изменится одинаковым способом.
Для идентификаторов особенно неприятно, что разные исходные значения могут стать равны. Потеряется не только красивый вывод: поиск, сравнение, ключи списка и обновление записи начнут ссылаться на неоднозначное представление. Восстановление всех цифр должно быть требованием к данным до использования, а не исправлением подписи в конце.
Проверенный учебный идентификатор
Возьмём вымышленное значение 9007199254740993. В малом локальном прогоне текущего Node числовой JSON с таким ID после JSON.parse дал 9007199254740992. Другой исходный ID 9007199254740992 стал тем же числом. Строковый вариант «9007199254740993» сохранил все знаки. Это проверка конкретного примера, не реальные данные сервиса.
| Этап | Учебное представление | Что получилось | Сохранились исходные цифры | Вывод для контракта |
|---|---|---|---|---|
| Исходный числовой JSON | id как число 9007199254740993 | В тексте ответа ещё нужные цифры | На этом этапе да | Синтаксически полученный текст не доказывает безопасный разбор клиентом |
| Обычный JSON.parse | То же числовое поле | Number со значением 9007199254740992 | Нет | Потеря уже произошла до отображения |
| String после этого разбора | Изменённое Number | Строка 9007199254740992 | Нет | Позднее изменение типа не возвращает источник |
| Согласованное строковое поле | id как строка 9007199254740993 | Та же строка после разбора | Да в проверенном прогоне | Сохранить этот тип в следующих слоях |
| Отправка строкового поля обратно | Строка после состояния и сериализации | Строка с теми же цифрами | Да в проверенном цикле | Проверять и получателя, а не только первый парсер |
Идентификатор не обязан участвовать в арифметике
Если значение нужно для связи с записью, поиска точного совпадения и передачи партнёру, числовое представление может не давать пользы. Строка также сохраняет ведущие нули, если они имеют смысл в выбранной системе. В учебном прогоне строка 000312 осталась 000312; перевод в число по другой политике изменил бы её представление.
Согласуйте допустимые символы, длину и правила сравнения. Не обрезайте пробелы, не удаляйте префиксы и не меняйте регистр без понятного договора. Сортировка текстовых идентификаторов и вычисления над количеством — разные задачи. Не превращайте любые похожие на цифры поля в Number одним общим преобразованием импортера.
Где строка снова становится числом
Проверьте клиентский адаптер, схему формы, промежуточную модель и сериализатор. Даже если сервер уже отправляет строку, библиотека или собственный код могут привести её к числу. Особенно внимательно исследуйте универсальные нормализаторы и справочники, где типы угадываются по содержимому. Уберите угадывание там, где контракт уже определён.
На интеграции через API тип должен совпадать у отправителя и получателя. Если одна сторона принимает только число, изменение клиента в одиночку может не решить проблему. Согласуйте новую схему и совместимость действующих потребителей. Старые повреждённые значения нельзя автоматически считать восстановленными после исправления будущих ответов.
Что может и чего не может reviver
Документация JSON.parse отмечает, что обычный разбор чисел происходит до вызова reviver. Поэтому String(value) для уже округлённого значения не извлекает исходный текст. Описан и специальный путь с context.source, позволяющим обратиться к исходному фрагменту; его поддержку и обработку нужно проверять в выбранной реализации.
Не смешивайте эти механизмы в обещании «reviver всегда спасёт». Если проект выбирает BigInt или специализированный парсер, согласуйте также хранение, сериализацию и обмен с остальными слоями. Это отдельный технический договор. Для текстовой идентичности основной строковый контракт часто проще объяснить и проверить, когда обе стороны могут его поддержать.
Приёмка всей цепочки
- Подготовьте вымышленные идентификаторы: обычный, граничный, два различающихся длинных значения и строку с ведущими нулями. Сохраните ожидаемый текст отдельно.
- Сравните сырой ответ и результат разбора, фиксируя значение вместе с типом. Найдите первое необратимое преобразование.
- Пройдите состояние формы, поиск и сравнение. Два разных учебных ID должны оставаться разными по согласованному контракту.
- Сохраните запись и разберите обратный результат. Проверяйте все цифры, а не длину подписи или округлённый вывод.
- Повторите обмен через применимые интеграции и импорт. Отдельно испытайте недопустимый тип, вместо молчаливой коррекции.
- Определите порядок разбора уже повреждённых записей по авторитетному источнику. Не восстанавливайте последние цифры догадкой.
При переносе данных в CRM зафиксируйте, какой источник считается исходным и как подтверждается соответствие. Удачный новый тест не доказывает чистоту старой базы. Результат исправления должен включать сохранённый тип, неизменность идентичности и понятную процедуру для прежних расхождений.
Вопросы и ответы
Что означает Number.MAX_SAFE_INTEGER?
Это граница безопасных целых для Number, равная 9007199254740991. Её нельзя путать с максимальным конечным значением типа или трактовать как одинаковое округление всех больших чисел.
Как передавать длинный ID при JSON.parse и BigInt?
Сначала согласуйте представление на стороне отправителя, например строковый идентификатор. Если выбран специальный парсер или BigInt, отдельно проверьте весь путь хранения и обратной сериализации.
Чем MAX_SAFE_INTEGER отличается от MAX_VALUE?
Первое относится к безопасности целочисленного представления и сравнения, второе — к максимальному конечному значению Number. Возможность хранить большое число ещё не означает сохранность всех цифр идентификатора.