Pull to refresh

Регистрозависимые ли ключи в JSON

Reading time2 min
Views6.7K

Конечно, да, скажете вы. Но не было бы этой статьи, если бы не было вопроса.

Так же эта статья будет вам полезна, если вы используете эквайринг от Тинькофф.

Немного предыстории. Какое-то время назад на одном из своих проектов я поменял онлайн-эквайринг на Тинькофф и уже после отладки начали всплывать странные ошибки с оплатой: хэш-подпись запроса считалась неверно. Причем, только на реальных платежах, что еще больше омрачало ситуацию.

Проблема оказалась в поле Data json-объекта, который приходит от банка в нотификации платежа. В одних случаях оно приходит как Data, а в других DATA (в верхнем регистре).

О проблеме я сообщил в поддержку Тинькофф и тут началось интересное. Поддержка утверждает, что регистр ключей в JSON не играет никакой роли:

Валерий, здравствуйте, JSON не является регистрозависимым. С его точки зрения DATA и Data это одно и тоже. Корень проблемы тут в вашем программном обеспечении, которое как раз регистрозависимое.

К сожалению, доказать обратное техническим специалистам Тинькофф не удалось. Найти упоминание регистрозависимости JSON в спецификации - еще более сложная задача (нашли), поэтому я поступил так, как делаю всегда: пишу код и проверяю как он работает.

Поскольку JSON сам по себе ничего не значит, а всегда обрабатывается каким-либо языком программирования, можно легко узнать, как те или иные языки относятся к ключам в разном регистре в JSON.

JavaScript - как самый популярный

Когда говорят про JSON, самым популярным языком, его использующим, является JS.

const json = JSON.parse('{"Data":1,"DATA":2}');
console.log(json, json.Data); // {Data: 1, DATA: 2} 1

Как видим, регистр ключей играет роль. Два разных ключа с разными значениями. И если в документации указан ключ Data, то DATA не подойдет, увы.

PHP - когда нет JS

Возможно будет разница между массивом и объектом?

<?php
$json = json_decode('{"Data":1,"DATA":2}', true);
var_dump($json);
// array (size=2)
//  'Data' => int 1
//  'DATA' => int 2

$json = json_decode('{"Data":1,"DATA":2}', false);
var_dump($json);
// object(stdClass)[253]
//  public 'Data' => int 1
//  public 'DATA' => int 2

Ситуация аналогичная. Ключи в разном регистре - это разные ключи. Преобразование в массив или в объект роли не играет.

Go - язык со строгой типизацией

Все же JS и PHP позволяют много вольностей. Возможно компилируемый язык со строгой типизацией будет вести себя иначе?

var data map[string]interface{}
json.Unmarshal([]byte("{\"Data\":1,\"DATA\":2}"), &data)
fmt.Println(data) // map[DATA:2 Data:1]

И снова ключи в разном регистре - это разные ключи. Мы получили map с двумя разными ключами и значениями.

C# - включаемая регистронезависимость

В комментариях выложили пример кода для C#

Поведение либо как у других языков, либо можно включить регистронезависимость и ловить ошибки при наложении свойств (хотя в случае одного свойства и правда не будет разницы).

Заключение

Если вы все еще сомневаетесь, является ли JSON регистрозависимым, просто попробуйте аналогичный код в своем языке программирования.

Я не встречал языка, в котором JSON был бы регистронезависимым. Если вы такой знаете - сообщите, будет интересно.

P.S. Я уверен, что разработчики Тинькофф тоже читают хабр. Обратите пожалуйста внимание на проблему. У вас на проде случайным образом меняется регистр ключа Data в нотификации платежа.

UPD 19.04.22 14:50

Спасибо @Busla за найденное упоминание регистрозависимости в спецификации.

Tags:
Hubs:
Total votes 7: ↑4 and ↓3+1
Comments23

Articles