Como analisar o JSON usando o Node.js?


972

Como devo analisar o JSON usando o Node.js? Existe algum módulo que validará e analisará o JSON com segurança?

Respostas:


1100

Você pode simplesmente usar JSON.parse.

A definição do JSONobjeto faz parte da especificação do ECMAScript 5 . O node.js foi criado no mecanismo V8 do Google Chrome , que segue o padrão ECMA. Portanto, o node.js também possui um objeto global [docs] .JSON

Nota - JSON.parsepode amarrar o segmento atual porque é um método síncrono. Portanto, se você estiver planejando analisar objetos JSON grandes, use um analisador json de streaming.


Alguém sabe por que isso não está na documentação oficial? Ou, se for, onde encontrá-lo?
precisa saber é o seguinte

34
@snapfractalpop: A documentação descreve apenas funções, etc, que fazem parte do node.js. Os recursos JavaScript padrão fazem parte da V8 , o node.js é construído. Eu atualizei a resposta de acordo.
Felix Kling

1
@FelixKling Por que vale a pena, há um monte de coisas aqui na wiki github do nó: github.com/joyent/node/wiki/...
damianb

aqui, publiquei uma demonstração em que você pode ver e jogar com esta resposta on-line (o exemplo de análise está no arquivo app.js - clique no botão executar e veja o resultado no terminal): link, você pode modificar o código e veja o impacto ...
nathan g

Sua resposta requer conhecimento prévio da sintaxe do JavaScript. Quão difícil seria mostrar um exemplo de uso? JSON.parse (str); // é a resposta simpático-Noob e, portanto, melhor
webb

661

você pode exigir arquivos .json.

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

Por exemplo, se você tiver um config.jsonarquivo no mesmo diretório do seu arquivo de código-fonte, você usaria:

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

ou (a extensão do arquivo pode ser omitida):

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

observe que requireé síncrono e lê o arquivo apenas uma vez ; as chamadas a seguir retornam o resultado do cache

Observe também que você só deve usar isso para arquivos locais sob seu controle absoluto, pois ele potencialmente executa qualquer código dentro do arquivo.


4
Se você estiver usando esse método para analisar o arquivo, certifique-se de levar o caminho em consideração para o requisito. Por exemplo, você pode precisar fazer algo assim: exigir './nome_do-arquivo-com- sem extensão' (por exemplo, se o arquivo estiver no diretório atual)
SnapShot

94
Observe que a resposta está em cache. Por exemplo, se você colocar acima, exigir chamada em uma função, chamar a função, alterar o arquivo JSON e chamar a função novamente, você obterá a versão antiga do arquivo JSON. Me pegou de fora algumas vezes!
Ben Clayton

15
Observe também que requireé síncrono. Se você deseja sincronizar o uso amigável fs.readFilecomJSON.parse
Evan Moran

29
Essa abordagem tratará apenas o arquivo como JavaScript, potencialmente executando código arbitrário no arquivo .json?
d11wtq

15
Nota simples: não se esqueça de usar a .jsonextensão! Se o seu arquivo NÃO tiver a .jsonextensão, o request não o tratará como um arquivo json.
Jason

323

Você pode usarJSON.parse() .

Você deve poder usar o JSONobjeto em qualquer implementação JavaScript compatível com ECMAScript 5 . E a V8 , na qual o Node.js é construído, é um deles.

Nota: Se você estiver usando um arquivo JSON para armazenar informações confidenciais (por exemplo, senhas), essa é a maneira errada de fazê-lo. Veja como o Heroku faz isso: https://devcenter.heroku.com/articles/config-vars#setting-up-config-vars-for-a-deployed-application . Descubra como sua plataforma faz isso e use process.envpara recuperar os vars de configuração de dentro do código.


Analisando uma sequência contendo dados JSON

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

Analisando um arquivo contendo dados JSON

Você terá que fazer algumas operações de arquivo com o fsmódulo

Versão assíncrona

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);
});

Versão síncrona

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

Você quer usar require? Pense de novo!

Às vezes você pode usarrequire :

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

Mas, eu não recomendo isso por vários motivos:

  1. requireé síncrono. Se você tiver um arquivo JSON muito grande, ele bloqueará seu loop de eventos. Você realmente precisa usar JSON.parsecom fs.readFile.
  2. requireirá ler o arquivo apenas uma vez . As chamadas subseqüentes requirepara o mesmo arquivo retornarão uma cópia em cache. Não é uma boa ideia se você deseja ler um .jsonarquivo que é atualizado continuamente. Você pode usar um hack . Mas, neste ponto, é mais fácil simplesmente usar fs.
  3. Se o seu arquivo não tiver uma .jsonextensão, requirenão tratará o conteúdo do arquivo como JSON.

A sério! UseJSON.parse .


load-json-file módulo

Se você está lendo um grande número de .jsonarquivos (e se você é extremamente preguiçoso), torna-se irritante escrever código padrão sempre. Você pode salvar alguns caracteres usando o load-json-filemódulo

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

Versão assíncrona

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

Versão síncrona

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

Analisando JSON de Fluxos

Se o conteúdo JSON for transmitido pela rede, você precisará usar um analisador JSON de streaming. Caso contrário, ele amarrará seu processador e bloqueará seu loop de eventos até que o conteúdo JSON seja totalmente transmitido.

Existem muitos pacotes disponíveis no NPM para isso. Escolha o que é melhor para você.


Tratamento de erros / segurança

Se você não tiver certeza se o que foi transmitido JSON.parse()é JSON válido , certifique-se de incluir a chamada JSON.parse()dentro de um try/catchbloco. Um usuário que forneceu uma string JSON pode travar seu aplicativo e até levar a falhas de segurança. Certifique-se de que a manipulação de erros seja realizada se você analisar o JSON fornecido externamente.


2
and could even lead to security holespor curiosidade, como?
Natario 28/10

6
@atario: Estamos falando de JS do lado do servidor aqui. Suponha que alguém esteja analisando JSON fornecido pelo usuário. Se a suposição for de que o JSON sempre esteja bem formado, um invasor poderá enviar algum JSON malformado para acionar um erro que, se espalhado para o lado do cliente, poderá revelar informações vitais sobre o sistema. Ou se o JSON estava malformado e continha algum texto <script>...e o erro foi derramado no lado do cliente, você tem um bug do XSS ali. Portanto, o IMO é importante para lidar com erros JSON exatamente onde você os analisa.
Sampathsris

1
@ NickSteele: No entanto, mudei "isso não é recomendado" para "Eu não recomendo". Espero que você esteja feliz agora.
precisa saber é o seguinte

1
@ NickSteele: Dadas as falhas que listei, não acho que seja um recurso bem projetado . Parece-me que algumas pessoas pensavam "ei, não seria legal usar requirepara incluir JSON?" e nem se deu ao trabalho de documentar os efeitos colaterais. Isso também significava que exigir aceita arquivos em dois idiomas: JavaScript e JSON (não, eles não são os mesmos). Tanta coisa para SRP.
precisa saber é o seguinte

1
@ NickSteele: Sim, apenas para a configuração funciona bem. Mas o JSON não é usado apenas para configuração.
precisa saber é o seguinte

85

use o objeto JSON :

JSON.parse(str);

12
Isso apenas duplica a resposta principal. Por favor, considere excluí-lo; você manterá os pontos.
Dan Dascalescu

6
Esta resposta tem 50 votos positivos. De acordo com a regra de 1% , provavelmente 5000 usuários passaram algum tempo lendo esta resposta, o que não acrescenta nada à primeira. O fato de que é 3 anos só piora o problema :)
Dan Dascalescu

16
@ DanDascalescu - Se você notar, as duas respostas foram postadas exatamente ao mesmo tempo há 3 anos. Ambos fornecem a mesma informação. Este é o caso em todo o SO, não vou selecionar metade das minhas respostas apenas porque não foram a resposta aceita.
Mark Kahn

8
Eu achei essa série de comentários bastante interessante, mas a resposta em si é uma perda de tempo. ... Não tenho certeza se isso implica que a resposta deve ser excluída, porque então eu não teria visto o tópico do comentário. Mas, caso contrário, eu diria que sim.
MalcolmOcean

7
@ DanDascalescu, acredito que esta resposta seja mais clara e direta ao ponto. O aceito não dá um exemplo de uso e é confuso por causa de muitos links e outras coisas extras.
andresgottlieb

37

Outro exemplo 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
Eu gosto que essa abordagem não exija que o arquivo json seja local para o aplicativo. Obrigado!
Charles Brandt

35

Eu gostaria de mencionar que existem alternativas para o objeto JSON global. JSON.parsee JSON.stringifysão síncronos; portanto, se você deseja lidar com grandes objetos, consulte alguns dos módulos JSON assíncronos.

Dê uma olhada: https://github.com/joyent/node/wiki/Modules#wiki-parsers-json


1
Isso é especialmente verdadeiro se se espera dados JSON de conexões de entrada. Se o JSON malformado estiver sendo analisado por JSON.parsetodo o aplicativo falhar ou, usando-o process.on('uncaughtException', function(err) { ... });, não haverá chance de enviar um erro "JSON malformado" ao usuário.
Paul

3
Qual é o asyncanalisador? Eu não encontrei isso.
bxshi

3
A página vinculada agora está marcada como "DEPRECATED" e se descreve como uma "relíquia desbotada".
ninguém

30

Inclua a node-fsbiblioteca.

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

Para mais informações sobre a biblioteca 'fs', consulte a documentação em http://nodejs.org/api/fs.html


2
Pode ser interessante notar que você deve agrupar sua linha de arquivo var em uma tentativa / captura, apenas no caso de seu JSON falhar na análise ou se o arquivo não existir.
Fostah 17/09/14

3
Ou apenas use um retorno de chamada!
lawx

10

Como você não sabe que sua string é realmente válida, eu a colocaria primeiro em uma tentativa. Além disso, como os blocos try catch não são otimizados por nó, eu colocaria a coisa inteira em outra função:

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

OU no "estilo assíncrono"

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

2
Eu só quero fazer uma anotação de que process.nextTick não é aysnc. É apenas adiar a leitura do arquivo até a próxima chamada de função no loop de eventos JS. Para executar JSON.parse forma assíncrona você tem usar uma linha diferente do que o thread principal Node.js
Alexander Mills

9

Analisando um fluxo JSON? Use 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 mundo aqui falou sobre JSON.parse, então pensei em dizer outra coisa. Há um ótimo módulo Conecte-se a muitos middlewares para facilitar e melhorar o desenvolvimento de aplicativos. Um dos middlewares é o bodyParser . Ele analisa JSON, html-forms e etc. Há também um middleware específico para JSON que analisa apenas noop .

Dê uma olhada nos links acima, pode ser realmente útil para você.



6

como outras respostas mencionadas aqui, você provavelmente deseja exigir um arquivo json local que você sabe que é seguro e presente, como um arquivo de configuração:

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

ou para usar o objeto JSON global para analisar um valor de sequência em um objeto:

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

Observe que, quando você exige um arquivo, o conteúdo desse arquivo é avaliado, o que apresenta um risco à segurança, caso não seja um arquivo json, mas um arquivo js.

publiquei uma demonstração em que é possível ver os dois métodos e jogar com eles on-line (o exemplo de análise está no arquivo app.js - clique no botão executar e veja o resultado no terminal): http: // staging1 .codefresh.io / labs / api / env / json-parse-example

você pode modificar o código e ver o impacto ...


5

Usando JSON para sua configuração com o Node.js? Leia isso e obtenha suas habilidades de configuração acima de 9000 ...

Nota: Pessoas que afirmam que dados = require ('./ data.json'); é um risco à segurança e rebate as respostas das pessoas com zelo zeloso: você está exatamente e completamente errado . Experimente colocar não-JSON naquele arquivo ... Nó lhe dará um erro, exatamente como seria se você fez a mesma coisa com o muito mais lento e mais difícil de código de leitura de arquivo manual e, em seguida, posterior JSON.parse (). Por favor, pare de espalhar informações erradas; você está machucando o mundo, não está ajudando. O nó foi projetado para permitir isso; não é um risco à segurança!

Os aplicativos adequados vêm em mais de 3 camadas de configuração:

  1. Configuração de servidor / contêiner
  2. Configuração do aplicativo
  3. (opcional) Configuração do inquilino / comunidade / organização
  4. Configuração do usuário

A maioria dos desenvolvedores trata suas configurações de servidor e aplicativo como se isso pudesse mudar. Não pode. Você pode colocar as alterações das camadas superiores umas sobre as outras, mas está modificando os requisitos básicos . Algumas coisas precisam existir! Faça sua configuração agir como se fosse imutável, porque parte disso é basicamente como o seu código-fonte.

Não perceber que muitas das suas coisas não serão alteradas após a inicialização leva a antipadrões, como desarrumar o carregamento da sua configuração com blocos try / catch e fingir que você pode continuar sem o aplicativo de configuração adequado. Você não pode. Se possível, isso pertence à camada de configuração da comunidade / usuário, não à camada de configuração do servidor / aplicativo. Você está fazendo errado. O material opcional deve ser colocado em camadas quando o aplicativo terminar sua inicialização.

Pare de bater com a cabeça na parede: sua configuração deve ser extremamente simples .

Veja como é fácil configurar algo tão complexo quanto uma estrutura de serviço independente de protocolo e independente de fonte de dados usando um arquivo json config simples e um arquivo app.js simples ...

container-config.js ...

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

index.js ... (o mecanismo que alimenta tudo)

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 ... (o código que alimenta seu serviço independente de protocolo e de origem de dados)

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

Usando esse padrão, agora você pode carregar itens de configuração da comunidade e do usuário sobre o aplicativo inicializado, o dev ops está pronto para colocar seu trabalho em um contêiner e escalá-lo. Você é lido para vários participantes. Userland é isolado. Agora você pode separar as preocupações sobre qual protocolo de serviço você está usando, qual tipo de banco de dados você está usando e se concentrar apenas em escrever um bom código.

Como você está usando camadas, pode confiar em uma única fonte de verdade para tudo, a qualquer momento (o objeto de configuração em camadas) e evitar verificações de erro a cada passo, preocupando-se com "oh droga, como vou fazer isso trabalhar sem a configuração adequada?!? ".


4

Minha solução:

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);
});

Obrigado @eloyesp, tentei usar esse código, mas continuo recebendo TypeError: path must be a string or Buffererros - alguma idéia de onde começar a depurar esse problema?
GPP 15/10

4

Só quero completar a resposta (como eu lutei com ela por um tempo), quero mostrar como acessar as informações do json, este exemplo mostra como acessar o 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

Apenas para tornar isso o mais complicado possível e trazer o maior número possível de pacotes ...

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);

Isso permite que você faça:

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

Ou se você estiver usando async / waitit:

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

A vantagem de apenas usar readFileSyncé que o servidor Node pode processar outras solicitações enquanto o arquivo está sendo lido no disco.


2

O JSON.parse não garantirá a segurança da string json que você está analisando. Você deve olhar para uma biblioteca como json-safe-parse ou uma biblioteca semelhante.

Na página json-safe-parse npm:

O JSON.parse é ótimo, mas possui uma falha séria no contexto do JavaScript: permite substituir propriedades herdadas. Isso pode se tornar um problema se você estiver analisando o JSON de uma fonte não confiável (por exemplo: um usuário) e chamando funções nele que você espera que exista.


2

Utilize a função de tentativa do Lodash para retornar um objeto de erro, que você pode manipular com a função 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
Você pode explicar por que você adicionou .bindao invés de apenas usar _.attempt (JSON.parse, str)
steviejay

2

Sempre certifique-se de usar JSON.parse em try catch block, pois o nó sempre gera um erro inesperado se você tiver alguns dados corrompidos em seu json; portanto, use esse código em vez de JSON.Parse simples

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

1

Se você quiser adicionar alguns comentários no seu JSON e permitir vírgulas finais, use a implementação abaixo:

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);
}

Observe que pode não funcionar bem se você tiver algo parecido "abc": "foo // bar"no seu JSON. Então YMMV.


1

Se o arquivo de origem JSON for muito grande, convém considerar a rota assíncrona por meio da abordagem nativa async / waitit com o Node.js. 8.0 da seguinte maneira

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

Eu uso fs-extra . Gosto muito porque, apesar de suportar retornos de chamada, também oferece suporte a Promises . Por isso, apenas me permite escrever meu código de uma maneira muito mais legível:

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

Ele também possui muitos métodos úteis que não acompanham o fsmódulo padrão e , além disso, também faz a ponte dos métodos do fsmódulo nativo e os promete.

NOTA: Você ainda pode usar os métodos nativos do Node.js. Eles são promissificados e copiados para o fs-extra. Veja notas sobre fs.read()&fs.write()

Então é basicamente todas as vantagens. Espero que outros achem isso útil.


1

Se você precisar analisar JSON com Node.js de maneira segura (ou seja: o usuário pode inserir dados ou uma API pública), sugiro usar secure-json-parse .

O uso é como o padrão, JSON.parsemas protegerá seu 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

Você pode usar JSON.parse () (que é uma função interna que provavelmente o forçará a envolvê-lo com instruções try-catch).

Ou use alguma biblioteca npm de análise JSON, algo como json-parse-or



0

O NodeJs é um servidor baseado em JavaScript , para que você possa fazer isso em JavaScript puro ...

Imagine que você tem esse Json em NodeJs ...

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

E você pode fazer acima para obter uma versão analisada do seu json ...


0

Conforme mencionado nas respostas acima, podemos usar JSON.parse()para analisar as seqüências de caracteres em JSON. Antes de analisar, certifique-se de analisar os dados corretos, caso contrário, poderá interromper o aplicativo inteiro

é seguro usá-lo assim

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

0

Use JSON.parse(str);. Leia mais sobre isso aqui .

aqui estão alguns exemplos:

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

Nenhum módulo adicional precisa ser necessário.
Basta usar.
var parsedObj = JSON.parse(yourObj);
Eu acho que existem problemas de segurança com relação a isso.


-2

É simples, você pode converter JSON em string usando JSON.stringify(json_obj)e converter string em JSON usando JSON.parse("your json string").


2
Você já viu a resposta principal para esta pergunta? Tem 3 anos e é muito completo. O que você esperava contribuir com as informações triviais que você está oferecendo aqui?
Robby Cornelissen

2
Agora, agora, não vamos realizar um duplo padrão
danielmhanover
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.