Допустимо ли определять функции в результатах JSON?


98

В части ответа JSON веб-сайта было это (... добавлено для контекста):

{..., now:function(){return(new Date).getTime()}, ...}

Допустимо ли добавление анонимных функций в JSON? Я ожидаю, что каждый раз, когда вы обращаетесь к «времени», вы получите другое значение.


Браузер успешно проанализировал JSON? Если да, то да, это действительно так (в этом отношении).
harschware 04

7
@harschware - это верно только потому, что JSON относится к javascript. Как формат сериализации данных, не зависящий от языка, он неверен и является проблематичным путем.
jsoverson

@jsoverson - согласен. Смотрите мой ответ ниже.
harschware 04

1
Легко для того чтобы ответить на этот вопрос самостоятельно: Откройте веб - комплект инспектор и запуск: JSON.parse('{now:function(){return(new Date).getTime()}'). Инспектор говорит: Uncaught SyntaxError: Unexpected token nбеглый взгляд на спецификацию JSON подтверждает это. Сосредоточьтесь на разделе «ценность».
Марк Э. Хаасе

Ответы:


103

Нет.

JSON предназначен исключительно для использования в качестве языка описания данных. Как отмечено на http://www.json.org , это «облегченный формат обмена данными». - не язык программирования.

Согласно http://en.wikipedia.org/wiki/JSON , поддерживаются следующие "основные типы":

  • Число (целое, действительное или с плавающей запятой)
  • Строка (Unicode в двойных кавычках с экранированием обратной косой черты)
  • Логическое (истина и ложь)
  • Массив (упорядоченная последовательность значений, разделенных запятыми и заключенных в квадратные скобки)
  • Объект (набор пар ключ: значение, разделенных запятыми и заключенных в фигурные скобки)
  • null

2
@ Д-р. Зим, нет, и чтобы сравнить вещи с null, что я делаю, это то, a==null?1:a.toString()==""что он делает, это говорит, что если a = null, то он возвращает 1 / true, если это "" означает пустую строку, вы также получаете 1 / true .. если это не null или "", тогда он вернет 0 / false, вы можете реплицировать это больше для работы с [] и {} просто просто добавляя ?1:a==[]?1:a.toString()=={}.toString();в мой предыдущий фрагмент. так что, возможно, эта функция вам поможет. isnull=(function(a){return (a==null?1:a.toString()==""?1:a==[]?1:a.toString()=={}.toString())?true:false})Я бы использовал ?1:0вместо ?true:falseно (истина / ложь)
JamesM-SiteGen

10
В то же время функции - это тоже данные.
argyle 01

2
Я приземлился здесь, когда искал способ получить «дополнительные данные» с помощью JSON. Было бы неплохо сообщить клиенту (с сервера), как получить дополнительные данные, чтобы клиент не беспокоился о том, какой REST или около того api вызвать следующим.
Равиндранат Акила

3
@RavindranathAkila REST подразумевает, что возможные следующие вызовы API отображаются в вызове. Другими словами: запрос REST, который вы сделали, сообщает вам, какие будущие запросы вы, возможно, захотите выполнить (на основе логики решения приложения и данных). Прекрасным примером для этого является API Github, где возвращаются элементы данных, но некоторые из них ведут к другим ресурсам запросов API.
Йенс А. Кох

1
@ Jens-AndréKoch Спасибо! Будет ли проверить это
Равиндранат Акила

16

Проблема в том, что JSON как язык определения данных развился из JSON как объектной нотации JavaScript. Поскольку Javascript поддерживает eval в JSON, можно разместить код JSON внутри JSON (в этом случае использования). Если вы используете JSON для удаленной передачи данных, то я бы сказал, что размещение методов в JSON - плохая практика, потому что вы, возможно, плохо смоделировали взаимодействие клиент-сервер. И, кроме того, если вы хотите использовать JSON в качестве языка описания данных, я бы сказал, что вы можете столкнуться с проблемами, встраивая методы, потому что некоторые парсеры JSON были написаны с учетом только описания данных и могут не поддерживать определения методов в структуре.

Запись JSON в Википедии дает хороший повод не включать методы в JSON, ссылаясь на соображения безопасности:

Если вы не полностью доверяете источнику текста и вам необходимо проанализировать и принять текст, который не является строго JSON-совместимым, вам следует избегать eval () и вместо этого использовать JSON.parse () или другой анализатор, специфичный для JSON. Парсер JSON распознает только текст JSON и отклонит другой текст, который может содержать вредоносный JavaScript. В браузерах, которые обеспечивают встроенную поддержку JSON, парсеры JSON также намного быстрее, чем eval. Ожидается, что встроенная поддержка JSON будет включена в следующий стандарт ECMAScript.


2
Вы можете использовать термин JSON в разговорной речи, но официально «JSON» - это стандарт ECMA, который не содержит только функциональных объектов, подлежащих кодированию. Не должно быть двусмысленности в том, какие возможности вы имеете в виду, когда говорите «JSON» - в этом весь смысл стандарта.
Марк Э. Хаасе

Согласились, что актуально сегодня. У меня нет источника для цитирования, но я считаю, что JSON был термином, придуманным до того, как ECMA вошла в игру Javascript, и до того, как JSON стал стандартным форматом обмена данными ... поэтому я использовал термин
``

@harschware Согласно RFC 4627, JSON был создан из ECMA.
Дженна Слоан

9

Процитируем одну из спецификаций - http://tools.ietf.org/html/rfc7159#section-12

В спецификации формата обмена данными JavaScript Object Notation (JSON) указано:

JSON - это подмножество JavaScript, но исключает назначение и вызов.

Поскольку синтаксис JSON заимствован из JavaScript, можно использовать функцию eval () этого языка для анализа текстов JSON. Обычно это представляет собой неприемлемую угрозу безопасности, поскольку текст
может содержать исполняемый код вместе с объявлениями данных
. То же самое относится к использованию функций, подобных eval (), в любом другом языке программирования, в котором тексты JSON соответствуют
синтаксису этого языка.

Итак, все ответы, в которых говорится, что функции не являются частью стандарта JSON, верны.

Официальный ответ: нет, определять функции в результатах JSON недопустимо!


Ответ может быть положительным, потому что «код - это данные», а «данные - это код». Даже если JSON используется как формат сериализации данных, не зависящий от языка, туннелирование «кода» через другие типы будет работать.

Строка JSON может использоваться для передачи функции JS браузеру на стороне клиента для выполнения.

[{"data":[["1","2"],["3","4"]],"aFunction":"function(){return \"foo bar\";}"}]

Это приводит к вопросу типа: «Как выполнить код JavaScript, хранящийся в виде строки ».

Будьте готовы поднять ваш флаг «eval () is evil» и прикрепить рядом с ним флаг «не туннелировать функции через JSON».



4

Нет, определенно нет.

Если вы используете достойный сериализатор JSON, он не позволит вам сериализовать такую ​​функцию. Это действительный ОБЪЕКТ, но недействительный JSON. Какими бы ни были намерения этого веб-сайта, он не отправляет действительный JSON.


2
Я использую JSON-Lib и считаю его отличным сериализатором. На [странице использования] (json-lib.sourceforge.net/usage.html) вы можете видеть, что он отлично сериализует функции
harschware

Интересно ... Я такого раньше не видел. Это определенно не для спецификации ( json.org явно заявляет, что JSON не зависит от языка, а определения функций - нет), но тем не менее интересно.
jvenema 05

Забавно, что он должен быть независимым от языка, но JSON расшифровывается как JavaScript Object Notation хм странно ..
Нейт-Уилкинс,

3

JSON явно исключает функции, потому что он не предназначен для использования в структуре данных только для JavaScript (несмотря на JS в названии).


3

Короткий ответ - НЕТ ...

JSON - это текстовый формат, который полностью не зависит от языка, но использует соглашения, знакомые программистам из семейства языков C, включая C, C ++, C #, Java, JavaScript, Perl, Python и многие другие. Эти свойства делают JSON идеальным языком обмена данными.

Посмотрите, почему:

При обмене данными между браузером и сервером данные могут быть только текстовыми.

JSON - это текст, и мы можем преобразовать любой объект JavaScript в JSON и отправить JSON на сервер.

Мы также можем преобразовать любой JSON, полученный с сервера, в объекты JavaScript.

Таким образом, мы можем работать с данными как с объектами JavaScript, без сложного синтаксического анализа и переводов.

Но подождите ...

Есть еще способы сохранить вашу функцию, это не рекомендуется , но все же возможно:

Мы сказали, вы можете сохранить string... а как насчет преобразования вашей функции в строку?

const data = {func: '()=>"a FUNC"'};

Затем вы можете структурировать данные, используя, JSON.stringify(data)а затем использовать JSON.parseдля их анализа (если этот шаг необходим) ...

И eval для выполнения строковой функции (перед этим просто дайте вам знать, что использование eval широко не рекомендуется):

eval(data.func)(); //return "a FUNC"

0

С помощью NodeJS (синтаксис commonJS) я смог заставить этот тип функциональности работать, изначально у меня была только структура JSON внутри некоторого внешнего файла JS, но я хотел, чтобы эта структура была больше классом, с методами, которые можно было бы решить на время выполнения.

Объявление Executor в myJSON не требуется.

var myJSON = {
    "Hello": "World",
    "Executor": ""
}

module.exports = {
    init: () => { return { ...myJSON, "Executor": (first, last) => { return first + last } } }
}

-3

Функциональные выражения в JSON вполне возможны, только не забудьте заключить его в двойные кавычки. Вот пример, взятый из проекта базы данных noSQL:

{
  "_id": "_design/testdb",
  "views": {
    "byName": {
      "map": "function(doc){if(doc.name){emit(doc.name,doc.code)}}"
    }
  }
}


Вопрос в функции, а не в строке. JSON поддерживает строковые значения, но не поддерживает функции. См ответа Майки для деталей
Яннис

@jannis, это возможно. если вы добавите самозапускающуюся функцию, например. люди здесь, по-видимому, просто не знают ответа.
Roj

-4

хотя eval не рекомендуется, это работает:

<!DOCTYPE html>
<html>
<body>

<h2>Convert a string written in JSON format, into a JavaScript function.</h2>

<p id="demo"></p>

<script>
    function test(val){return val + " it's OK;}
    var someVar = "yup";
    var myObj = { "func": "test(someVar);" };
    document.getElementById("demo").innerHTML = eval(myObj.func);
</script>

</body>
</html>

1
проголосовали против, потому что в этом примере нет необходимости использовать HTML, это 5-летний стиль кодирования, отсутствует цитата, и файлы JSON не должны содержать функции, если они это сделают, они не могут быть сериализованы или сохранены в a no sql DB,
Мартейн Шеффер

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.