Est-il valide de définir des fonctions dans les résultats JSON?

98

Une partie de la réponse JSON d'un site Web avait ceci (... ajouté pour le contexte):

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

L'ajout de fonctions anonymes à JSON est-il valide? Je m'attendrais à chaque fois que vous accédez à «time» pour renvoyer une valeur différente.

Zachary Scott
la source
Le JSON a-t-il été analysé avec succès par le navigateur? Si tel est le cas, oui, c'est valable (à cet égard).
harschware
7
@harschware - cela n'est vrai que dans la mesure où JSON se rapporte à javascript. En tant que format de sérialisation de données indépendant du langage, il est faux et constitue un chemin problématique à parcourir.
jsoverson le
@jsoverson - Je suis d'accord. Voir ma réponse ci-dessous.
harschware
1
Facile à répondre à cette question vous: ouvert inspecteur kit web et exécution: JSON.parse('{now:function(){return(new Date).getTime()}'). L'inspecteur dit: Uncaught SyntaxError: Unexpected token nUn rapide coup d'œil à la spécification JSON le confirme. Concentrez-vous sur la section «valeur».
Mark E. Haase

Réponses:

103

Non.

JSON est uniquement destiné à être un langage de description de données. Comme indiqué sur http://www.json.org , il s'agit d'un «format léger d'échange de données». - pas un langage de programmation.

Selon http://en.wikipedia.org/wiki/JSON , les "types de base" pris en charge sont:

  • Nombre (entier, réel ou virgule flottante)
  • Chaîne (Unicode entre guillemets doubles avec échappement de barre oblique inverse)
  • Booléen (vrai et faux)
  • Tableau (une séquence ordonnée de valeurs, séparées par des virgules et entre crochets)
  • Object (collection de clés: paires de valeurs, séparées par des virgules et entourées d'accolades)
  • null
Mike
la source
2
@Dr. Zim, non et pour comparer les choses à null, ce que je fais est ceci a==null?1:a.toString()=="". non null ou "" alors il retournera 0 / false, vous pouvez le répliquer davantage pour travailler avec [] et {} simplement ajouter ?1:a==[]?1:a.toString()=={}.toString();à mon extrait de code précédent. alors peut-être que cette fonction vous aidera. isnull=(function(a){return (a==null?1:a.toString()==""?1:a==[]?1:a.toString()=={}.toString())?true:false})J'utiliserais à la ?1:0place de ?true:falsemais (vrai / faux)
JamesM-SiteGen
10
En même temps, les fonctions sont aussi des données.
argyle
2
J'ai atterri ici en trouvant un moyen de récupérer "d'autres données" en utilisant JSON. Ce serait bien d'informer un client (à partir du serveur) de la manière d'obtenir des données supplémentaires, sans que le client se soucie du REST ou de l'API à appeler ensuite.
Ravindranath Akila
3
@RavindranathAkila REST implique que les prochains appels API possibles sont exposés dans l'appel. En d'autres termes: la demande REST que vous avez effectuée vous indique quelles demandes futures vous voudrez peut-être faire (en fonction de la logique de décision de l'application et des données). Un exemple parfait pour cela est l'API Github, où les éléments de données sont renvoyés - mais certains d'entre eux mènent à d'autres ressources de demande d'API.
Jens A. Koch
1
@ Jens-AndréKoch Merci! Je vais le vérifier
Ravindranath Akila
16

Le problème est que JSON en tant que langage de définition de données a évolué à partir de JSON en tant que notation d'objet JavaScript. Puisque Javascript prend en charge eval sur JSON, il est légitime de mettre du code JSON dans JSON (dans ce cas d'utilisation). Si vous utilisez JSON pour transmettre des données à distance, je dirais que c'est une mauvaise pratique de mettre des méthodes dans le JSON car vous n'avez peut-être pas bien modélisé votre interaction client-serveur. Et, en outre, lorsque vous souhaitez utiliser JSON comme langage de description de données, je dirais que vous pourriez vous créer des problèmes en intégrant des méthodes, car certains analyseurs JSON ont été écrits avec uniquement la description des données à l'esprit et peuvent ne pas prendre en charge les définitions de méthode dans la structure.

L'entrée JSON de Wikipedia est un bon argument pour ne pas inclure de méthodes dans JSON, citant des problèmes de sécurité:

À moins que vous ne fassiez entièrement confiance à la source du texte et que vous ayez besoin d'analyser et d'accepter du texte qui n'est pas strictement conforme à JSON, vous devez éviter eval () et utiliser JSON.parse () ou un autre analyseur spécifique JSON à la place. Un analyseur JSON reconnaîtra uniquement le texte JSON et rejettera tout autre texte, qui pourrait contenir du JavaScript malveillant. Dans les navigateurs offrant une prise en charge native de JSON, les analyseurs JSON sont également beaucoup plus rapides que eval. Il est prévu que le support JSON natif soit inclus dans la prochaine norme ECMAScript.

harschware
la source
2
Vous utilisez peut-être le terme JSON de manière familière, mais officiellement "JSON" est une norme ECMA qui ne dépouille pas les objets de fonction à encoder. Il ne devrait y avoir aucune ambiguïté quant aux capacités auxquelles vous faites référence lorsque vous dites "JSON" - c'est tout l'intérêt d'avoir un standard.
Mark E. Haase
Convenu que c'est vrai aujourd'hui. Je n'ai pas de source à citer, mais je crois que JSON était un terme inventé avant que ECMA n'entre dans le jeu Javascript, et avant que JSON soit un format d'échange de données standard ... j'ai donc utilisé le terme `` évolué ''
harschware
@harschware Selon RFC 4627, JSON a été créé à partir d'ECMA.
Jenna Sloan
9

Citons l'une des spécifications - http://tools.ietf.org/html/rfc7159#section-12

La spécification du format d'échange de données The JavaScript Object Notation (JSON) indique:

JSON est un sous-ensemble de JavaScript mais exclut l'affectation et l'appel.

Puisque la syntaxe de JSON est empruntée à JavaScript, il est possible d'utiliser la fonction "eval ()" de ce langage pour analyser les textes JSON. Cela constitue généralement un risque de sécurité inacceptable, car le texte
peut contenir du code exécutable avec des déclarations de données
. La même considération s'applique à l'utilisation des fonctions de type eval () dans tout autre langage de programmation dans lequel les textes JSON sont conformes à
la syntaxe de ce langage.

Donc, toutes les réponses indiquant que les fonctions ne font pas partie de la norme JSON sont correctes.

La réponse officielle est: Non, il n'est pas valide de définir des fonctions dans les résultats JSON!


La réponse pourrait être oui, car «le code est une donnée» et «la donnée est un code». Même si JSON est utilisé comme format de sérialisation de données indépendant du langage, un tunneling de «code» à travers d'autres types fonctionnera.

Une chaîne JSON peut être utilisée pour transmettre une fonction JS au navigateur côté client pour exécution.

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

Cela conduit à des questions comme: Comment « exécuter du code JavaScript stocké sous forme de chaîne ».

Soyez prêt, pour lever votre drapeau "eval () is evil" et coller votre drapeau "Ne pas tunneler les fonctions via JSON" à côté.

Jens A. Koch
la source
7

Ce n'est pas standard pour autant que je sache. Un rapide coup d'œil sur http://json.org/ le confirme.

jldupont
la source
4

Non, certainement pas.

Si vous utilisez un sérialiseur JSON décent, il ne vous permettra pas de sérialiser une fonction comme celle-là. C'est un OBJET valide, mais pas un JSON valide. Quelle que soit l'intention de ce site Web, il n'envoie pas de JSON valide.

jvenema
la source
2
J'utilise JSON-Lib et le considère comme un excellent sérialiseur. Sur la [page d'utilisation] (json-lib.sourceforge.net/usage.html), vous pouvez voir qu'il sérialisera très bien les fonctions
harschware
Intéressant ... Je n'ai jamais vu ça auparavant. Ce n'est certainement pas une spécification ( json.org indique explicitement que JSON est indépendant du langage, quelles définitions de fonction ne le sont pas), mais néanmoins intéressant.
jvenema le
C'est drôle que ce soit censé être indépendant du langage, mais JSON signifie JavaScript Object Notation hmm weird ..
Nate-Wilkins
3

JSON exclut explicitement les fonctions car il n'est pas censé être une structure de données JavaScript uniquement (malgré le JS dans le nom).

Tatu Ulmanen
la source
3

Une réponse courte est NON ...

JSON est un format de texte complètement indépendant du langage, mais qui utilise des conventions familières aux programmeurs de la famille de langages C, notamment C, C ++, C #, Java, JavaScript, Perl, Python et bien d'autres. Ces propriétés font de JSON un langage d'échange de données idéal.

Regardez la raison pour laquelle:

Lors de l'échange de données entre un navigateur et un serveur, les données ne peuvent être que du texte.

JSON est du texte et nous pouvons convertir n'importe quel objet JavaScript en JSON et envoyer JSON au serveur.

Nous pouvons également convertir tout JSON reçu du serveur en objets JavaScript.

De cette façon, nous pouvons travailler avec les données en tant qu'objets JavaScript, sans analyse ni traductions compliquées.

Mais attendez ...

Il existe encore des moyens de stocker votre fonction, ce n'est généralement pas recommandé , mais toujours possible:

Nous avons dit, vous pouvez enregistrer un string... que diriez-vous alors de convertir votre fonction en chaîne?

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

Ensuite, vous pouvez stringify les données en utilisant JSON.stringify(data)puis en utilisant JSON.parsepour les analyser (si cette étape est nécessaire) ...

Et eval pour exécuter une fonction de chaîne (avant de faire cela, faites-vous simplement savoir en utilisant eval largement déconseillé):

eval(data.func)(); //return "a FUNC"
Alireza
la source
0

En utilisant NodeJS (syntaxe commonJS), j'ai pu faire fonctionner ce type de fonctionnalité, j'avais à l'origine juste une structure JSON dans un fichier JS externe, mais je voulais que cette structure soit plus une classe, avec des méthodes qui pourraient être décidées à Durée.

La déclaration de 'Executor' dans myJSON n'est pas requise.

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

module.exports = {
    init: () => { return { ...myJSON, "Executor": (first, last) => { return first + last } } }
}
Mitchell Spangler
la source
-3

Les expressions de fonction dans le JSON sont tout à fait possibles, n'oubliez pas de les mettre entre guillemets. Voici un exemple tiré de la conception de base de données noSQL:

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

Eimantas Pėlikis
la source
La question concerne une fonction et non une chaîne. JSON prend en charge les valeurs de chaîne, mais il ne prend pas en charge les fonctions. Voir la réponse de Mike pour plus de détails
jannis
@jann est cependant possible. si vous ajoutez une fonction auto-appelante comme. les gens ici ne connaissent apparemment tout simplement pas la réponse.
Roj
-4

bien qu'éval ne soit pas recommandé, cela fonctionne:

<!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>
pascati
la source
1
a voté contre car il n'est pas nécessaire d'utiliser HTML dans l'exemple, il s'agit d'un style de codage vieux de 5 ans, il manque une citation et, les fichiers JSON ne sont pas censés contenir des fonctions, s'ils le font, ils ne peuvent pas être sérialisés ou stockés dans a no sql DB,
Martijn Scheffer
-5

Laissez les guillemets ...

var a = {"b":function(){alert('hello world');} };

a.b();
Clif Collins
la source
C'est du JavaScript, la question se pose sur JSON.
Quentin