如何使用Node.js?解析JSON

我应该如何解析JSON使用Node.js?有一些模块将验证和解析JSON安全?

1033185 次浏览

您可以简单地使用JSON.parse

JSON对象是ECMAScript 5规范的一部分.node.js的定义建立在GoogleChrome的V8引擎上,它遵循ECMA标准。因此,node.js也有一个全局对象#0[docs]

注意-JSON.parse可以捆绑当前线程,因为它是一个同步方法。因此,如果您计划解析大JSON对象,请使用流json解析器。

使用JSON对象

JSON.parse(str);

您可以要求. json文件。

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

例如,如果您在与源代码文件相同的目录中有一个config.json文件,您将使用:

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

或(文件扩展名可以省略):

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

请注意,require同步并且只读取文件一次,以下调用从缓存返回结果

另请注意,您应该仅将其用于您绝对控制下的本地文件,因为它可能会执行文件中的任何代码。

我想提一下全局JSON对象的替代方案。JSON.parseJSON.stringify都是同步的,所以如果你想处理大对象,你可能需要检查一些异步JSON模块。

看看:https://github.com/joyent/node/wiki/Modules#wiki-parsers-json

JSON.parse("your string");

仅此而已。

这里的每个人都说过JSON.parse,所以我想说点别的。有一个很棒的模块连接,里面有许多中间件,可以让应用程序的开发更容易、更好。其中一个中间件是身体解析器。它解析JSON、html表单等。还有一个特定的中间件只解析JSONnoop

看看上面的链接,可能对你有帮助。

解析JSON流?使用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

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

由于你不知道你的字符串实际上是有效的,我会先把它放在一个try catch中。此外,由于try catch块没有被节点优化,我会把整个东西放在另一个函数中:

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

或者在“异步风格”中

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

包括node-fs库。

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

有关'fs'库的更多信息,请参阅http://nodejs.org/api/fs.html的留档

很简单,您可以使用JSON.stringify(json_obj)将JSON转换为字符串,并使用JSON.parse("your json string")将字符串转换为JSON。

您可以使用#0.

您应该能够在任何ECMAScript 5兼容的JavaScript实现上使用JSON对象。构建Node.js的V8就是其中之一。

注意:如果您使用JSON文件来存储敏感信息(例如密码),那是错误的做法。看看Heroku是如何做到的:https://devcenter.heroku.com/articles/config-vars#setting-up-config-vars-for-a-deployed-application。了解您的平台是如何做到的,并使用process.env从代码中检索配置变量。


解析包含JSON数据的字符串

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

解析包含JSON数据的文件

您必须使用fs模块执行一些文件操作。

异步版本

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 nowvar obj = JSON.parse(data);});

同步版本

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

你想用0号吗?再想想!

有时可以使用#0

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

但是,我不建议这样做,原因有几个:

  1. require是同步的。如果你有一个非常大的JSON文件,它会阻塞你的事件循环。你真的需要使用JSON.parsefs.readFile
  2. require将读取文件只有一次。对同一文件的后续调用require将返回缓存副本。如果您想读取不断更新的.json文件,这不是一个好主意。您可以使用一个黑客。但在这一点上,简单地使用fs更容易。
  3. 如果您的文件没有.json扩展名,require不会将文件的内容视为JSON。

真的!使用#0.


load-json-file模块

如果您正在阅读大量的.json文件(如果您非常懒惰),每次编写样板代码都会变得很烦人。您可以使用load-json-file模块保存一些字符。

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

异步版本

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

同步版本

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

从流中解析JSON

如果JSON内容通过网络流式传输,您需要使用流式JSON解析器。否则它会占用您的处理器并阻塞您的事件循环,直到JSON内容完全流式传输。

这有在NPM中提供大量软件包。选择最适合你的。


错误处理/安全性

如果您不确定传递给JSON.parse()的是不是有效的JSON,请确保将对JSON.parse()的调用包含在try/catch块中。用户提供的JSON字符串可能会使您的应用程序崩溃,甚至可能导致安全漏洞。如果您解析外部提供的JSON,请确保完成错误处理。

正如这里提到的其他答案,您可能需要一个您知道安全且存在的本地json文件,例如配置文件:

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

或者使用全局JSON对象将字符串值解析为对象:

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

请注意,当您需要一个文件时,会评估该文件的内容,这会带来安全风险,以防它不是json文件而是js文件。

在这里,我发布了一个演示,您可以在其中看到这两种方法并在线使用它们(解析示例在app.js文件中-然后单击运行按钮并在终端中查看结果):http://staging1.codefresh.io/labs/api/env/json-parse-example

您可以修改代码并查看影响…

JSON.parse不能确保您正在解析的json字符串的安全性。您应该查看像JSON安全解析这样的库或类似的库。

从json-asse-parse npm页面:

JSON.parse很棒,但它在JavaScript上下文中有一个严重的缺陷:它允许您覆盖继承的属性。如果您从不受信任的源(例如:用户)解析JSON并在其上调用您期望存在的函数,这可能会成为一个问题。

我的解决方案:

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

利用Lodash的尝试函数返回一个错误对象,您可以使用isError函数处理该对象。

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

// Example Usagevar 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
var fs = require('fs');
fs.readFile('ashish.json',{encoding:'utf8'},function(data,err) {
if(err)throw err;
else {
console.log(data.toString());
}})

始终确保使用尝试捕获块中的JSON.parse作为节点,如果您的json中有一些损坏的数据,则始终抛出意外错误,因此请使用此代码而不是简单的JSON. Parse

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

只是为了让这件事尽可能复杂,并带来尽可能多的包裹…

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

这可以让你做:

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

或者如果您使用的是async/wait:

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

与仅使用readFileSync相比,优点在于您的Node服务器可以在文件从磁盘读取时处理其他请求。

只是想完成答案(因为我挣扎了一会儿),想展示如何访问json信息,这个例子显示了访问Json数组:

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

如果你想在你的JSON中添加一些注释并允许尾随逗号,你可能需要在概念下面使用:

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

请注意,如果您的JSON中包含类似"abc": "foo // bar"的内容,它可能无法正常工作。所以YMMV。

使用JSON为您的配置与Node.js?阅读这篇文章,让你的配置技能超过9000…

注意:声称data=需要('./data.json');是一个安全风险和以狂热的热情否决人们的回答:你完全是错了。尝试在该文件中放置非JSON… Node会给你一个错误,完全,就像你对做同样的事情一样,更慢更难地编写手动文件读取,然后是后续的JSON.parse()。请停止传播虚假信息;你在伤害世界,没有帮助。节点是设计允许这样做;这不是一个安全风险!

正确的应用程序有3+图层的配置:

  1. 服务器/容器配置
  2. 应用配置
  3. (可选)租户/社区/组织配置
  4. 用户配置

大多数开发人员对待他们的服务器和应用程序配置就好像它可以改变一样。它不能。你可以从更高的层开始层变化,但你是修改基本要求。有些东西需要存在!让你的配置表现得像是不可变的,因为它的一些基本上是不可变的,就像你的源代码一样。

没有看到你的很多东西在启动后不会改变会导致反模式,比如在你的配置加载中乱扔try/cat块,并假装你可以继续没有正确设置的应用程序。你不能。如果可以,那属于社区/用户配置层,而不是服务器/应用程序配置层。你只是做错了。当应用程序完成引导时,可选的东西应该放在最上面。

不要把你的头撞在墙上:你的配置应该是超简单

看看使用简单的json配置文件和简单的app.js文件设置像协议无关和数据源无关的服务框架这样复杂的东西是多么容易。

container-config.js.…

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

index.js.…(驱动一切的引擎)

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.…(为协议无关和数据源无关服务提供支持的代码)

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

使用此模式,你现在可以在启动的应用程序之上加载社区和用户配置内容,开发人员已准备好将你的工作推入容器并扩展它。你被读取为多租户。Userland是隔离的。你现在可以将你使用的服务协议和你使用的数据库类型的关注点分开,然后专注于编写好的代码。

因为你使用的是图层,所以你可以在任何时候依赖可信单一数据源(分层配置对象),并避免在每一步进行错误检查,担心“哦,废话,如果没有适当的配置,我怎么能让这个工作?!?”。

您可以使用JSON.parse()(这是一个内置函数,可能会迫使您使用try-cat语句包装它)。

或者使用一些JSON解析npm库,比如json-parse-or是否需要解析

为了安全起见用这个吧

var data = JSON.parse(Buffer.concat(arr).toString());

使用JSON.parse(str);。阅读更多关于它的信息这里

以下是一些例子:

var jsonStr = '{"result":true, "count":42}';
obj = JSON.parse(jsonStr);
console.log(obj.count);    // expected output: 42console.log(obj.result);   // expected output: true

不需要其他模块。
只需使用
var parsedObj = JSON.parse(yourObj);
我不认为这有任何安全问题

如果JSON源文件非常大,可能需要考虑通过原生async/wait方法使用Node.js8.0的异步路由,如下所示

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

我使用fs-额外。我非常喜欢它,因为-尽管它支持回调-它也支持Promises。所以它使我能够以更具可读性的方式编写我的代码:

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

它还有许多有用的方法,这些方法没有与标准的fs模块一起出现,最重要的是,它还桥接了来自本机fs模块的方法并对它们进行了预测。

注意:您仍然可以使用原生Node.js方法。它们被promisify并复制到fs-额外。请参阅fs.read()fs.write()上的注释

所以基本上都是优点。我希望其他人觉得这有用。

nodejs是基于javascript的服务器,因此您可以在纯javascript中执行此操作…

假设你有这个Jsonnodejs

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

您可以执行上述操作以获取json的解析版本…

如上所述,我们可以使用JSON.parse()将字符串解析为JSON但在解析之前,请务必解析正确的数据,否则可能会使整个应用程序停机

这样使用是安全的

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

如果你需要用Node.js安全的方式解析JSON(也就是:用户可以输入数据或公共API),我建议使用安全json解析

用法类似于默认的JSON.parse,但它会保护您的代码免受:

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