¿Cómo analizar JSON usando Node.js?


972

¿Cómo debería analizar JSON usando Node.js? ¿Hay algún módulo que valide y analice JSON de forma segura?

Respuestas:


1100

Puedes simplemente usar JSON.parse.

La definición del JSONobjeto es parte de la especificación ECMAScript 5 . node.js se basa en el motor V8 de Google Chrome , que se adhiere al estándar ECMA. Por lo tanto, node.js también tiene un objeto global [docs] .JSON

Nota: JSON.parsepuede atar el hilo actual porque es un método sincrónico. Entonces, si planea analizar grandes objetos JSON, use un analizador de json de transmisión.


Alguien sabe por qué eso no está en la documentación oficial? O, si es así, ¿dónde encontrarlo?
snapfractalpop

34
@snapfractalpop: la documentación solo describe funciones, etc., que forman parte de node.js. Las características estándar de JavaScript son parte de V8 , en el que se basa node.js. Actualicé la respuesta en consecuencia.
Felix Kling

1
@FelixKling Para lo que vale, hay un montón de cosas aquí en el wiki de github del nodo: github.com/joyent/node/wiki/…
damianb

aquí, publiqué una demostración donde puede ver y jugar con esta respuesta en línea (el ejemplo de análisis está en el archivo app.js, luego haga clic en el botón Ejecutar y vea el resultado en el terminal): enlace puede modificar el código y ver el impacto ...
nathan g

Su respuesta requiere un conocimiento previo de la sintaxis de JavaScript. ¿Qué tan difícil sería mostrar un ejemplo de uso? JSON.parse (str); // es la respuesta novato de usar y por lo tanto mejor
Webb

661

puede requerir archivos .json.

var parsedJSON = require('./file-name');

Por ejemplo, si tiene un config.jsonarchivo en el mismo directorio que su archivo de código fuente, usaría:

var config = require('./config.json');

o (se puede omitir la extensión del archivo):

var config = require('./config');

tenga en cuenta que requirees sincrónico y solo lee el archivo una vez , las siguientes llamadas devuelven el resultado del caché

También tenga en cuenta que solo debe usar esto para archivos locales bajo su control absoluto, ya que potencialmente ejecuta cualquier código dentro del archivo.


44
Si está utilizando este método para analizar el archivo, asegúrese de tener en cuenta la ruta para el requisito. Por ejemplo, es posible que deba hacer algo como esto: requerir './file-name-with-no-extension' (por ejemplo, si el archivo está en el directorio actual)
SnapShot

94
Tenga en cuenta que la respuesta está en caché. Por ejemplo, si se pone por encima de la llamada necesita en una función, llamar a la función, cambie el archivo JSON, y llamar de nuevo la función, que obtendrá la antigua versión del archivo JSON. ¡Me ha pillado un par de veces!
Ben Clayton

15
Tenga en cuenta también que requirees sincrónico. Si quieres asíncrono uso amigable fs.readFileconJSON.parse
Evan Moran

29
¿Este enfoque solo tratará el archivo como JavaScript, por lo tanto, posiblemente ejecute código arbitrario en el archivo .json?
d11wtq

15
Nota simple: ¡no olvides usar la .jsonextensión! Si su archivo NO tiene la .jsonextensión, require no lo tratará como un archivo json.
Jason

323

Puedes usarJSON.parse() .

Debería poder utilizar el JSONobjeto en cualquier implementación de JavaScript compatible con ECMAScript 5 . Y V8 , sobre el cual se construye Node.js, es uno de ellos.

Nota: Si está utilizando un archivo JSON para almacenar información confidencial (por ejemplo, contraseñas), esa es la forma incorrecta de hacerlo. Vea cómo lo hace Heroku: https://devcenter.heroku.com/articles/config-vars#setting-up-config-vars-for-a-deployed-application . Descubra cómo lo hace su plataforma y úsela process.envpara recuperar los valores de configuración desde el código.


Analizando una cadena que contiene datos JSON

var str = '{ "name": "John Doe", "age": 42 }';
var obj = JSON.parse(str);

Analizando un archivo que contiene datos JSON

Tendrás que hacer algunas operaciones de archivo con el fsmódulo.

Versión asincrónica

var fs = require('fs');

fs.readFile('/path/to/file.json', 'utf8', function (err, data) {
    if (err) throw err; // we'll not consider error handling for now
    var obj = JSON.parse(data);
});

Versión sincrónica

var fs = require('fs');
var json = JSON.parse(fs.readFileSync('/path/to/file.json', 'utf8'));

Quieres usar require? ¡Piensa otra vez!

A veces puedes usarrequire :

var obj = require('path/to/file.json');

Pero no recomiendo esto por varias razones:

  1. requirees sincrónico Si tiene un archivo JSON muy grande, ahogará su bucle de eventos. Realmente necesitas usar JSON.parsecon fs.readFile.
  2. requireleerá el archivo solo una vez . Las llamadas posteriores al requiremismo archivo devolverán una copia en caché. No es una buena idea si desea leer un .jsonarchivo que se actualiza continuamente. Podrías usar un truco . Pero en este punto, es más fácil de usar fs.
  3. Si su archivo no tiene una .jsonextensión, requireno tratará el contenido del archivo como JSON.

¡Seriamente! UsoJSON.parse .


load-json-file módulo

Si está leyendo una gran cantidad de .jsonarchivos (y si es extremadamente vago), se vuelve molesto escribir código repetitivo cada vez. Puede guardar algunos caracteres usando el load-json-filemódulo.

const loadJsonFile = require('load-json-file');

Versión asincrónica

loadJsonFile('/path/to/file.json').then(json => {
    // `json` contains the parsed object
});

Versión sincrónica

let obj = loadJsonFile.sync('/path/to/file.json');

Analizando JSON desde transmisiones

Si el contenido JSON se transmite a través de la red, debe usar un analizador JSON de transmisión. De lo contrario, atará su procesador y estrangulará su bucle de eventos hasta que el contenido JSON se transmita por completo.

Hay muchos paquetes disponibles en NPM para esto. Elige lo que sea mejor para ti.


Manejo de errores / seguridad

Si no está seguro de si lo que se le pasa JSON.parse()es JSON válido , asegúrese de encerrar la llamada JSON.parse()dentro de un try/catchbloque. Una cadena JSON proporcionada por el usuario podría bloquear su aplicación e incluso podría generar agujeros de seguridad. Asegúrese de que el manejo de errores se realiza si analiza JSON proporcionado externamente.


2
and could even lead to security holespor curiosidad, ¿cómo?
natario

66
@natario: Estamos hablando de JS del lado del servidor aquí. Supongamos que alguien está analizando JSON proporcionado por el usuario. Si se supone que el JSON siempre está bien formado, un atacante puede enviar un JSON mal formado para desencadenar un error, que si se derrama al lado del cliente, puede revelar información vital sobre el sistema. O si el JSON fue malformado y contenía algo de texto <script>..., y el error se derramó en el lado del cliente, tiene un error XSS allí mismo. Por lo tanto, es importante manejar los errores JSON justo donde lo analiza.
sampathsris

1
@NickSteele: Sin embargo, cambié "esto no se recomienda" a "No lo recomiendo". Espero que estés feliz ahora.
sampathsris

1
@NickSteele: Dadas las fallas que he enumerado, no creo que sea una característica bien diseñada . Me parece que algunas personas pensaron "oye, ¿no sería genial usar requirepara incluir a JSON?" y ni siquiera se molestó en documentar los efectos secundarios. Esto también significa que requiere aceptar archivos en dos idiomas: JavaScript y JSON (no, no son lo mismo). Demasiado para SRP.
sampathsris

1
@NickSteele: Sí, solo para la configuración funciona bien. Pero JSON no se usa solo para la configuración.
sampathsris

85

usa el objeto JSON :

JSON.parse(str);

12
Esto simplemente duplica la respuesta superior. Por favor considere eliminarlo; mantendrás los puntos.
Dan Dascalescu

66
Esta respuesta tiene 50 votos a favor. De acuerdo con la regla del 1% , probablemente 5000 usuarios hayan pasado tiempo leyendo esta respuesta, lo que no agrega nada al primero. El hecho de que tenga 3 años solo empeora el problema :)
Dan Dascalescu

16
@DanDascalescu: si se da cuenta, las dos respuestas se publicaron exactamente al mismo tiempo hace 3 años. Ambos proporcionan la misma información. Este es el caso en todo SO, no voy a eliminar la mitad de mis respuestas solo porque no fueron la respuesta aceptada.
Mark Kahn el

8
Por mi parte, esta serie de comentarios me pareció bastante interesante, pero la respuesta en sí misma fue una pérdida de tiempo. ... No estoy seguro de si eso implica que la respuesta debería eliminarse, porque entonces no habría visto el hilo de comentarios. Pero de lo contrario diría que sí.
MalcolmOcean

77
@DanDascalescu, creo que esta respuesta es más clara y directa. El aceptado no da un ejemplo de uso y es confuso debido a muchos enlaces y cosas adicionales.
andresgottlieb

37

Otro ejemplo de JSON.parse:

var fs = require('fs');
var file = __dirname + '/config.json';

fs.readFile(file, 'utf8', function (err, data) {
  if (err) {
    console.log('Error: ' + err);
    return;
  }

  data = JSON.parse(data);

  console.dir(data);
});

2
Me gusta que este enfoque no requiera que el archivo json sea local para la aplicación. ¡Gracias!
Charles Brandt

35

Me gustaría mencionar que hay alternativas al objeto JSON global. JSON.parsey JSON.stringifyambos son síncronos, por lo que si desea tratar con objetos grandes, es posible que desee consultar algunos de los módulos JSON asíncronos.

Echa un vistazo: https://github.com/joyent/node/wiki/Modules#wiki-parsers-json


1
Esto es especialmente cierto si uno espera datos JSON de las conexiones entrantes. Si JSON.parsetoda la aplicación analiza el JSON con formato incorrecto, se bloqueará o, al usarlo process.on('uncaughtException', function(err) { ... });, eventualmente no habrá posibilidad de enviar un error de "JSON con formato incorrecto" al usuario.
Paul

3
¿Cuál es el asyncanalizador sintáctico? No lo encontré.
bxshi

3
La página vinculada ahora está marcada como "DEPRECADA" y se describe a sí misma como una "reliquia desvaída".
nadie

30

Incluye la node-fsbiblioteca.

var fs = require("fs");
var file = JSON.parse(fs.readFileSync("./PATH/data.json", "utf8"));

Para obtener más información sobre la biblioteca 'fs', consulte la documentación en http://nodejs.org/api/fs.html


2
Vale la pena señalar que debe ajustar la línea de su archivo var en un try / catch en caso de que su JSON no se pueda analizar o el archivo no exista.
Fostah

3
¡O simplemente use una devolución de llamada!
lawx

10

Como no sabe que su cadena es realmente válida, la pondría primero en un intento de captura. Además, dado que los bloques try catch no están optimizados por nodo, pondría todo en otra función:

function tryParseJson(str) {
    try {
        return JSON.parse(str);
    } catch (ex) {
        return null;
    }
}

O en "estilo asíncrono"

function tryParseJson(str, callback) {
    process.nextTick(function () {
      try {
          callback(null, JSON.parse(str));
      } catch (ex) {
          callback(ex)
      }
    })
}

2
Solo quiero anotar que process.nextTick no es aysnc. Simplemente está posponiendo la lectura del archivo hasta la próxima llamada de función en el bucle de eventos JS. Para ejecutar JSON.parse de forma asincrónica, ha utilizado un hilo diferente al hilo principal Node.js
Alexander Mills,

9

Analizando una secuencia JSON? Uso JSONStream.

var request = require('request')
  , JSONStream = require('JSONStream')

request({url: 'http://isaacs.couchone.com/registry/_all_docs'})
    .pipe(JSONStream.parse('rows.*'))
    .pipe(es.mapSync(function (data) {
      return data
    }))

https://github.com/dominictarr/JSONStream


7

Todo el mundo aquí ha contado sobre JSON.parse, así que pensé en decir algo más. Hay un gran módulo Conéctese con muchos middleware para hacer que el desarrollo de aplicaciones sea más fácil y mejor. Uno de los middleware es bodyParser . Analiza JSON, formularios html, etc. También hay un middleware específico para JSON que analiza solo noop .

Eche un vistazo a los enlaces de arriba, podría ser realmente útil para usted.



6

Como han mencionado otras respuestas aquí, probablemente desee solicitar un archivo json local que sepa que es seguro y presente, como un archivo de configuración:

var objectFromRequire = require('path/to/my/config.json'); 

o para usar el objeto JSON global para analizar un valor de cadena en un objeto:

var stringContainingJson = '\"json that is obtained from somewhere\"';
var objectFromParse = JSON.parse(stringContainingJson);

tenga en cuenta que cuando necesita un archivo, se evalúa el contenido de ese archivo, lo que introduce un riesgo de seguridad en caso de que no sea un archivo json sino un archivo js.

aquí, publiqué una demostración en la que puede ver ambos métodos y jugar con ellos en línea (el ejemplo de análisis está en el archivo app.js, luego haga clic en el botón Ejecutar y vea el resultado en el terminal): http: // staging1 .codefresh.io / labs / api / env / json-parse-example

puedes modificar el código y ver el impacto ...


5

¿Usa JSON para su configuración con Node.js? Lea esto y obtenga sus habilidades de configuración por encima de 9000 ...

Nota: Las personas que afirman que data = require ('./ data.json'); es un riesgo para la seguridad y rechazar las respuestas de las personas con celo celoso: estás exactamente y completamente equivocado . Intente colocar no JSON en ese archivo ... Node le dará un error, exactamente como lo haría si hiciera lo mismo con la lectura de archivos manual mucho más lenta y difícil de codificar y luego JSON.parse (). Por favor, deje de difundir información errónea; estás lastimando al mundo, no ayudando. Node fue diseñado para permitir esto; ¡No es un riesgo de seguridad!

Las aplicaciones adecuadas vienen en más de 3 capas de configuración:

  1. Configuración del servidor / contenedor
  2. Configuración de la aplicación
  3. (opcional) Configuración de inquilino / comunidad / organización
  4. Configuración de usuario

La mayoría de los desarrolladores tratan la configuración de su servidor y aplicación como si pudiera cambiar. No puede Puede superponer cambios de capas superiores una encima de otra, pero está modificando los requisitos básicos . ¡Algunas cosas necesitan existir! Haga que su configuración actúe como si fuera inmutable, porque parte de ella básicamente lo es, al igual que su código fuente.

No ver que muchas de sus cosas no van a cambiar después del inicio conduce a antipatrones como ensuciar su carga de configuración con bloques try / catch y pretender que puede continuar sin su aplicación de configuración adecuada. No puedes Si puede, eso pertenece a la capa de configuración de comunidad / usuario, no a la capa de configuración de servidor / aplicación. Solo lo estás haciendo mal. Las cosas opcionales deben colocarse en capas en la parte superior cuando la aplicación finalice su arranque.

Deja de golpearte la cabeza contra la pared: tu configuración debe ser ultra simple .

Eche un vistazo a lo fácil que es configurar algo tan complejo como un marco de servicio independiente del protocolo y del origen de datos utilizando un archivo de configuración json simple y un archivo app.js simple ...

container-config.js ...

{
    "service": {
        "type"  : "http",
        "name"  : "login",
        "port"  : 8085
    },
    "data": {
        "type"  : "mysql",
        "host"  : "localhost",
        "user"  : "notRoot",
        "pass"  : "oober1337",
        "name"  : "connect"
    }
}

index.js ... (el motor que impulsa todo)

var config      = require('./container-config.json');       // Get our service configuration.
var data        = require(config.data.type);            // Load our data source plugin ('npm install mysql' for mysql).
var service     = require(config.service.type);         // Load our service plugin ('http' is built-in to node).
var processor   = require('./app.js');                  // Load our processor (the code you write).

var connection  = data.createConnection({ host: config.data.host, user: config.data.user, password: config.data.pass, database: config.data.name });
var server      = service.createServer(processor);
connection.connect();
server.listen(config.service.port, function() { console.log("%s service listening on port %s", config.service.type, config.service.port); });

app.js ... (el código que impulsa su servicio independiente de protocolo y fuente de datos)

module.exports = function(request, response){
    response.end('Responding to: ' + request.url);
}

Con este patrón, ahora puede cargar cosas de configuración de la comunidad y del usuario en la parte superior de su aplicación arrancada, las operaciones de desarrollo están listas para llevar su trabajo a un contenedor y escalarlo. Estás leído para multiempresa. Userland está aislado. Ahora puede separar las preocupaciones de qué protocolo de servicio está usando, qué tipo de base de datos está usando, y simplemente centrarse en escribir un buen código.

Debido a que está utilizando capas, puede confiar en una única fuente de verdad para todo, en cualquier momento (el objeto de configuración en capas) y evitar verificaciones de errores en cada paso, preocupándose por "oh mierda, ¿cómo voy a hacer esto? funciona sin la configuración adecuada?!? ".


4

Mi solución:

var fs = require('fs');
var file = __dirname + '/config.json';

fs.readFile(file, 'utf8', function (err, data) {
    if (err) {
        console.log('Error: ' + err);
        return;
    }

    data = JSON.parse(data);

    console.dir(data);
});

Gracias @eloyesp, intenté usar este código pero sigo recibiendo TypeError: path must be a string or Buffererrores. ¿ Alguna idea de dónde comenzar a depurar este problema?
GPP

4

Solo quiero completar la respuesta (mientras luché con ella por un tiempo), quiero mostrar cómo acceder a la información json, este ejemplo muestra cómo acceder a Json Array:

var request = require('request');
request('https://server/run?oper=get_groups_joined_by_user_id&user_id=5111298845048832', function (error, response, body) {
  if (!error && response.statusCode == 200) {
    var jsonArr = JSON.parse(body);
    console.log(jsonArr);
    console.log("group id:" + jsonArr[0].id);
  }
})


3

Solo para hacer esto lo más complicado posible, y traer tantos paquetes como sea posible ...

const fs = require('fs');
const bluebird = require('bluebird');
const _ = require('lodash');
const readTextFile = _.partial(bluebird.promisify(fs.readFile), _, {encoding:'utf8',flag:'r'});
const readJsonFile = filename => readTextFile(filename).then(JSON.parse);

Esto te permite hacer:

var dataPromise = readJsonFile("foo.json");
dataPromise.then(console.log);

O si está utilizando async / await:

let data = await readJsonFile("foo.json");

La ventaja sobre el uso readFileSynces que su servidor Node puede procesar otras solicitudes mientras el archivo se lee desde el disco.


2

JSON.parse no garantizará la seguridad de la cadena json que está analizando. Debería mirar una biblioteca como json-safe-parse o una biblioteca similar.

Desde la página nson json-safe-parse:

JSON.parse es excelente, pero tiene una falla grave en el contexto de JavaScript: le permite anular las propiedades heredadas. Esto puede convertirse en un problema si está analizando JSON desde una fuente no confiable (por ejemplo: un usuario), y llamando a funciones que esperaría que existieran.


2

Aproveche la función de intento de Lodash para devolver un objeto de error, que puede manejar con la función isError.

// Returns an error object on failure
function parseJSON(jsonString) {
   return _.attempt(JSON.parse.bind(null, jsonString));
}


// Example Usage
var goodJson = '{"id":123}';
var badJson = '{id:123}';
var goodResult = parseJSON(goodJson);
var badResult = parseJSON(badJson);

if (_.isError(goodResult)) {
   console.log('goodResult: handle error');
} else {
   console.log('goodResult: continue processing');
}
// > goodResult: continue processing

if (_.isError(badResult)) {
   console.log('badResult: handle error');
} else {
   console.log('badResult: continue processing');
}
// > badResult: handle error

3
¿Puede explicar por qué agregó en .bindlugar de simplemente usar _.attempt (JSON.parse, str)
steviejay

2

Siempre asegúrese de usar JSON.parse en try catch block ya que el nodo siempre arroja un Error inesperado si tiene algunos datos corruptos en su json, así que use este código en lugar de JSON.Parse simple

try{
     JSON.parse(data)
}
catch(e){
   throw new Error("data is corrupted")
  }

1

Si desea agregar algunos comentarios en su JSON y permitir las comas finales, puede usar la siguiente implementación:

var fs = require('fs');

var data = parseJsData('./message.json');

console.log('[INFO] data:', data);

function parseJsData(filename) {
    var json = fs.readFileSync(filename, 'utf8')
        .replace(/\s*\/\/.+/g, '')
        .replace(/,(\s*\})/g, '}')
    ;
    return JSON.parse(json);
}

Tenga en cuenta que podría no funcionar bien si tiene algo como "abc": "foo // bar"en su JSON. Entonces YMMV.


1

Si el archivo fuente JSON es bastante grande, puede considerar la ruta asincrónica a través del enfoque asíncrono / espera nativo con Node.js 8.0 de la siguiente manera

const fs = require('fs')

const fsReadFile = (fileName) => {
    fileName = `${__dirname}/${fileName}`
    return new Promise((resolve, reject) => {
        fs.readFile(fileName, 'utf8', (error, data) => {
            if (!error && data) {
                resolve(data)
            } else {
                reject(error);
            }
        });
    })
}

async function parseJSON(fileName) {
    try {
        return JSON.parse(await fsReadFile(fileName));
    } catch (err) {
        return { Error: `Something has gone wrong: ${err}` };
    }
}

parseJSON('veryBigFile.json')
    .then(res => console.log(res))
    .catch(err => console.log(err))

1

Yo uso fs-extra . Me gusta mucho porque, aunque admite devoluciones de llamada, también admite Promesas . Entonces solo me permite escribir mi código de una manera mucho más legible:

const fs = require('fs-extra');
fs.readJson("path/to/foo.json").then(obj => {
    //Do dome stuff with obj
})
.catch(err => {
    console.error(err);
});

También tiene muchos métodos útiles que no vienen junto con el fsmódulo estándar y , además de eso, también fsune los métodos del módulo nativo y los promete.

NOTA: aún puede utilizar los métodos nativos de Node.js. Son prometidos y copiados a fs-extra. Ver notas sobre fs.read()&fs.write()

Así que básicamente son todas las ventajas. Espero que otros encuentren esto útil.


1

Si necesita analizar JSON con Node.js de forma segura (también conocido como: el usuario puede ingresar datos o una API pública), sugeriría usar secure-json-parse .

El uso es el predeterminado, JSON.parsepero protegerá su código de:

const badJson = '{ "a": 5, "b": 6, "__proto__": { "x": 7 }, "constructor": {"prototype": {"bar": "baz"} } }'

const infected = JSON.parse(badJson)
console.log(infected.x) // print undefined

const x = Object.assign({}, infected)
console.log(x.x) // print 7

const sjson = require('secure-json-parse')
console.log(sjson.parse(badJson)) // it will throw by default, you can ignore malicious data also

0

Puede usar JSON.parse () (que es una función integrada que probablemente lo obligará a envolverlo con declaraciones try-catch).

O utilice alguna biblioteca npm de análisis JSON, algo como json-parse-or



0

NodeJs es un servidor basado en JavaScript , por lo que puede hacer lo que hace en JavaScript puro ...

Imagina que tienes este Json en NodeJs ...

var details = '{ "name": "Alireza Dezfoolian", "netWorth": "$0" }';
var obj = JSON.parse(details);

Y puede hacer lo anterior para obtener una versión analizada de su json ...


0

Como se menciona en las respuestas anteriores, podemos usar JSON.parse() para analizar las cadenas a JSON. Pero antes de analizar, asegúrese de analizar los datos correctos o de lo contrario podría hacer que su aplicación se caiga.

es seguro usarlo así

let parsedObj = {}
try {
    parsedObj = JSON.parse(data);
} catch(e) {
    console.log("Cannot parse because data is not is proper json format")
}

0

Uso JSON.parse(str);. Lea más sobre esto aquí .

Aquí hay unos ejemplos:

var jsonStr = '{"result":true, "count":42}';

obj = JSON.parse(jsonStr);

console.log(obj.count);    // expected output: 42
console.log(obj.result);   // expected output: true

-1

No se necesitan más módulos.
Simplemente use
var parsedObj = JSON.parse(yourObj);
No creo que haya problemas de seguridad con respecto a esto


-2

Es simple, puede convertir JSON a cadena usando JSON.stringify(json_obj), y convertir cadena a JSON usando JSON.parse("your json string").


2
¿Has mirado la respuesta superior para esta pregunta? Tiene 3 años y es muy completo. ¿Qué esperabas contribuir con la información trivial que ofreces aquí?
Robby Cornelissen

2
Ahora, ahora, no mantengamos un doble rasero
danielmhanover
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.