如何使用Node.js解析JSON?


Answers:


1098

您可以简单地使用JSON.parse

JSON对象的定义是ECMAScript 5规范的一部分。node.js基于Google Chrome的V8引擎构建,该引擎遵循ECMA标准。因此,node.js也有一个全局对象[docs]JSON

注意- JSON.parse可以占用当前线程,因为它是一种同步方法。因此,如果您打算解析大型JSON对象,请使用流式JSON解析器。


有人知道官方文档中为什么没有吗?或者,如果是,在哪里找到它?
snapfractalpop 2012年

34
@snapfractalpop:文档仅描述了函数等,它们是node.js的一部分。标准JavaScript功能是V8的一部分,node.js构建在此之上。我相应地更新了答案。
Felix Kling 2012年

1
@FelixKling关于它的价值,在节点的github Wiki上有一堆东西:github.com/joyent/node/wiki/…–
damianb

在这里,我已经发布了一个演示,您可以在其中在线查看和使用此答案(解析示例位于app.js文件中-然后单击“运行”按钮并在终端中查看结果): 可以修改代码的链接并看到影响...
森·克

您的答案需要具备JavaScript语法的先验知识。显示用法示例有多难?JSON.parse(str); //是
菜鸟

660

您可以要求 .json文件。

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

例如,如果您的config.json文件与源代码文件位于同一目录中,则可以使用:

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

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

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

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

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


4
如果您使用此方法来解析文件,请确保考虑到需要的路径。例如,您可能需要执行以下操作:require'./file-name-with-no-extension'(例如,如果文件位于当前目录中)
SnapShot

94
请注意,响应被缓存。例如,如果您在函数中放置了require调用,然后调用该函数,更改JSON文件,然后再次调用该函数,则将获得版本的JSON文件。吸引了我几次!
本·克莱顿

15
另请注意,这require是同步的。如果你想异步友好的使用fs.readFile,而不是用JSON.parse
埃文·莫兰

29
这种方法是否会将文件视为JavaScript,从而可能在.json文件中运行任意代码?
d11wtq

15
简单说明:不要忘记使用.json扩展名!如果您的文件没有.json扩展名,则require不会将其视为json文件。
杰森

323

您可以使用JSON.parse()

您应该能够JSON在任何ECMAScript 5兼容的JavaScript实现上使用该对象。而构建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 now
    var obj = JSON.parse(data);
});

同步版本

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

你想用require吗?再想一想!

您有时可以使用require

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

但是,出于以下几个原因,我不建议您这样做:

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

认真!使用JSON.parse


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,请确保已完成错误处理。


2
and could even lead to security holes出于好奇,怎么办?
natario

6
@natario:我们在这里谈论服务器端JS。假设有人正在解析用户提供的JSON。如果假设JSON始终格式正确,则攻击者可以发送一些格式错误的JSON来触发错误,如果该错误传播到客户端,则可能会泄露有关系统的重要信息。或者,如果JSON格式不正确,并且包含带有的文本<script>...,并且该错误已泄漏到客户端,那么您那里就有一个XSS错误。因此,IMO必须在解析的正确位置处理JSON错误,这一点很重要。
sampathsris '16

1
@NickSteele:但是,我将“不推荐”更改为“我不推荐”。我希望你现在开心。
sampathsris

1
@NickSteele:考虑到我列出的缺陷,我认为这不是一个精心设计的功能。在我看来,有些人认为“嘿,使用requireJSON 会很酷吗?” 甚至都没有记录副作用。这也意味着require接受两种语言的文件:JavaScript和JSON(不,它们是不一样的)。SRP太多了。
sampathsris

1
@NickSteele:是的,仅适用于配置。但是JSON不仅用于配置。
sampathsris

85

使用JSON对象

JSON.parse(str);

12
这只是复制最佳答案。请考虑删除它;您将保留要点。
Dan Dascalescu 2014年

6
该答案有50个投票。根据1%的规则,可能有5000位用户花了时间阅读此答案,但对排名靠前的内容一无所获。它已经存在3年了,这个事实只会使问题更糟:)
Dan Dascalescu 2014年

16
@DanDascalescu-如果您会注意到,这两个答案是在3年前的同一时间发布的。它们都提供相同的信息。整个情况都是这样,我不会因为自己未接受答案而去掉一半的答案。
Mark Kahn 2014年

8
我曾经发现这一系列评论相当有趣,但答案本身却浪费了我的时间。...我不确定这是否意味着应该删除答案,因为那样我就不会看到评论主题。但是否则我会说的。
MalcolmOcean'Aug

7
@DanDascalescu,我相信这个答案更清楚,直接。接受的没有给出用法示例,并且由于存在许多链接和额外的内容而令人困惑。
andresgottlieb

37

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
我喜欢这种方法,不需要json文件位于应用程序本地。谢谢!
查尔斯·勃兰特

35

我想提一下,全局JSON对象还有其他选择。 JSON.parse并且JSON.stringify都是同步的,因此如果您要处理大对象,则可能需要检出一些异步JSON模块。

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


1
如果人们期望传入连接中的JSON数据,则尤其如此。如果JSON.parse整个应用程序都在分析格式错误的JSON ,或者使用崩溃,process.on('uncaughtException', function(err) { ... });最终将没有机会向用户发送“格式错误的JSON”错误。
Paul

3
async解析器是哪一个?我没找到。
bxshi

3
链接的页面现在标记为“已弃用”,并将其自身描述为“褪色的遗物”。
没人


10

由于您不知道您的字符串实际上是有效的,因此我将其放在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)
      }
    })
}

2
我只想说明一下process.nextTick不是aysnc。它只是推迟读取文件,直到JS事件循环中的下一个函数调用为止。要异步运行JSON.parse,请使用与Node.js主线程不同的线程
Alexander Mills 2015年


7

这里的每个人都讲过JSON.parse,所以我想说些别的。有一个很棒的模块,可以与许多中间件连接,以使应用程序的开发变得更轻松,更好。中间件之一是bodyParser。它解析JSON,html表单等。还有一个特定的中间件,用于仅解析noop的 JSON 。

看一下上面的链接,它可能对您真的很有帮助。



6

就像这里提到的其他答案一样,您可能需要使用一个已知的安全且存在的本地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

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


5

使用JSON与Node.js进行配置?阅读本文,获得超过9000的配置技能...

注意:人们声称data = require('./ data.json'); 这是一种安全隐患,并且会以热心的热情低估人们的回答:您是完全错误的。尝试将非JSON在该文件中...节点会给你一个错误,正是像它会如果你没有用同样的事情很多慢,更难代码手册文件的读取,然后随后的JSON.parse()来。请停止散布错误信息;您在伤害世界,无济于事。Node被设计为允许这样做;这不是安全隐患!

正确的应用程序包含3 以上的配置:

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

大多数开发人员将其服务器和应用程序配置视为可以更改的。不行 您可以将高层的更改彼此叠加,但是您正在修改基本需求。有些事情需要存在!使您的配置看起来像是不可变的,因为其中的一些基本上就像源代码一样。

在启动导致反模式后,未能看到很多东西不会改变,例如用try / catch块乱扔您的配置加载,并且假装您可以在没有正确设置应用程序的情况下继续。你不能 如果可以的话,它属于社区/用户配置层,而不是服务器/应用程序配置层。你只是做错了。当应用程序完成引导时,可选内容应放在顶部。

停止将头撞在墙上:您的配置应该非常简单

看看使用简单的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);
}

使用此模式,您现在可以在启动的应用程序顶部加载社区和用户配置内容,开发人员可以将您的工作推入容器并进行扩展。您正在阅读多租户。用户区是隔离的。现在,您可以区分所使用的服务协议,所使用的数据库类型的关注点,而只专注于编写良好的代码。

因为你使用的图层,你可以依靠真理的一切的单一来源,在任何时候(分层配置对象),并在每一步避免错误检查,担心“哦废话,我应该如何去作这个没有正确的配置就可以工作?!?”。


4

我的解决方案:

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

感谢@eloyesp,我尝试使用此代码,但始终TypeError: path must be a string or Buffer出现错误-知道从哪里开始调试此问题?
GPP

4

只是想完成答案(我在一段时间内苦苦挣扎),想展示如何访问json信息,此示例显示了如何访问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

只是为了使其尽可能复杂,并引入尽可能多的软件包...

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

或者,如果您使用的是异步/等待:

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

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


2

JSON.parse无法确保您解析的json字符串的安全。您应该查看json-safe-parse之类的库或类似的库。

从json-safe-parse npm页面:

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


2

利用Lodash的try函数返回错误对象,您可以使用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
您能解释一下为什么添加.bind而不是仅使用_.attempt(JSON.parse,str)的原因
steviejay

2

始终确保在try catch块中使用JSON.parse,因为如果json中有一些损坏的数据,则节点总是会引发意外错误,因此请使用此代码而不是简单的JSON.Parse

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

1

如果要在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);
}

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


1

如果JSON源文件很大,则可能要考虑使用Node.js 8.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))

1

我使用fs-extra。我非常喜欢它,因为-尽管它支持回调-它也支持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模块和promisifies他们。

注意:您仍然可以使用本机Node.js方法。它们被承诺并复制到fs-extra。请参阅fs.read()fs.write()

因此,这基本上是所有优点。我希望其他人觉得这有用。


1

如果您需要以安全的方式使用Node.js解析JSON(又名:用户可以输入数据或公共API),则建议使用secure-json-parse

用法类似于默认用法,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

0

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

或使用JSON解析npm库,例如json-parse-or



0

NodeJs是基于JavaScript的服务器,因此您可以采用纯JavaScript的方式进行操作...

假设您在NodeJ中有这个Json ...

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

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


0

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

这样可以安全使用

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

0

使用JSON.parse(str);在此处了解更多信息。

这里有些例子:

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

无需其他模块。
只是使用
var parsedObj = JSON.parse(yourObj);
我不认为与此有关的任何安全问题


-2

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


2
您是否已查看此问题的最高答案?它已经3岁了,非常完整。您希望对这里提供的琐碎信息做出什么贡献?
罗比·科尼利森

2
现在,现在,让我们不要采用双重标准
danielmhanover
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.