【问题标题】:How to parse JSON using Node.js? [closed]如何使用 Node.js 解析 JSON? [关闭]
【发布时间】:2011-08-09 06:18:46
【问题描述】:

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

【问题讨论】:

    标签: javascript json node.js


    【解决方案1】:

    您可以简单地使用JSON.parse

    JSON 对象is part of the ECMAScript 5 specification 的定义。 node.js 建立在 Google Chrome 的 V8 引擎之上,该引擎遵循 ECMA 标准。因此,node.js 也有一个全局对象JSON[docs]

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

    【讨论】:

    • 有人知道为什么官方文档中没有吗?或者,如果是的话,在哪里可以找到它?
    • @snapfractalpop:文档只描述了函数等,它们是 node.js 的一部分。标准 JavaScript 功能是 V8 的一部分,node.js 是在此基础上构建的。我相应地更新了答案。
    • @FelixKling 对于它的价值,这里有一堆东西在 node 的 github wiki 上:github.com/joyent/node/wiki/…
    • 在这里,我发布了一个演示,您可以在其中在线查看和使用此答案(解析示例在 app.js 文件中 - 然后单击运行按钮并在终端中查看结果):link你可以修改代码看看效果...
    • 您的答案需要事先了解 JavaScript 语法。展示一个使用示例有多难? JSON.parse(str); // 是菜鸟友好的,因此更好的答案
    【解决方案2】:

    你可以require.json 文件。

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

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

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

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

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

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

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

    【讨论】:

    • 如果您使用此方法解析文件,请确保将路径考虑在内。例如,您可能需要执行以下操作: require './file-name-with-no-extension' (例如,如果文件在当前目录中)
    • 请注意,响应是缓存的。例如。如果你把上面的 require 调用放在一个函数中,调用该函数,更改 JSON 文件,然后再次调用该函数,你将得到 JSON 文件的 old 版本。已经抓到我几次了!
    • 还要注意require 是同步的。如果你想友好地异步使用 fs.readFile 而不是 JSON.parse
    • 这种方法是否会将文件视为 JavaScript,从而可能会在 .json 文件中运行任意代码?
    • 简单说明:不要忘记使用.json 扩展名!如果您的文件没有.json 扩展名,require 不会将其视为 json 文件。
    【解决方案3】:

    您可以使用JSON.parse()

    您应该能够在任何与 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 now
        var obj = JSON.parse(data);
    });
    

    同步版本

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

    你想使用require?再想想!

    You can sometimes use require:

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

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

    1. require 是同步的。如果你有一个非常大的 JSON 文件,它会阻塞你的事件循环。您确实需要将JSON.parsefs.readFile 一起使用。
    2. require只读取一次文件。随后对同一文件的require 调用将返回一个缓存副本。如果您想阅读不断更新的.json 文件,这不是一个好主意。你可以使用a 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 内容完全流式传输。

    这里有plenty of packages available in NPM。选择最适合您的。


    错误处理/安全

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

    【讨论】:

    • and could even lead to security holes 出于好奇,怎么样?
    • @natario:我们在这里讨论的是服务器端 JS。假设有人正在解析用户提供的 JSON。如果假设 JSON 始终格式正确,则攻击者可以发送一些格式错误的 JSON 来触发错误,如果该错误溢出到客户端,可能会泄露有关系统的重要信息。或者,如果 JSON 格式不正确并且包含一些带有 <script>... 的文本,并且错误溢出到客户端,那么您就有一个 XSS 错误。因此,IMO 在您解析它的地方处理 JSON 错误非常重要。
    • @NickSteele:但是,我将“不推荐”改为“不推荐”。我希望你现在快乐。
    • @NickSteele:鉴于我列出的缺陷,我不认为这是一个精心设计的功能。在我看来,有些人认为“嘿,使用 require 包含 JSON 不是很酷吗?”甚至没有费心记录副作用。这也意味着 require 接受两种语言的文件:JavaScript 和 JSON(不,它们不一样)。 SRP 就这么多。
    • @NickSteele:是的,只有配置才能正常工作。但是 JSON 不仅仅用于配置。
    【解决方案4】:

    使用JSON object:

    JSON.parse(str);
    

    【讨论】:

    • 这只是重复了最佳答案。请考虑删除它;你会保留积分。
    • 这个答案有 50 个赞。根据1% rule 的说法,可能有 5000 名用户已经花时间阅读了这个答案,这对排名靠前的答案没有任何帮助。它已经 3 岁的事实只会让问题变得更糟:)
    • @DanDascalescu -- 如果您注意到,这两个答案是在 3 年前完全相同的时间发布的。它们都提供相同的信息。整个情况都是如此,我不会仅仅因为它们不是公认的答案而剔除一半的答案。
    • 我发现这一系列的 cmets 相当有趣,但答案本身就是在浪费我的时间。 ...我不确定这是否意味着应该删除答案,因为那样我就不会看到评论线程。但否则我会说是的。
    • @DanDascalescu,我相信这个答案更清晰,直截了当。接受的没有给出使用示例,并且由于许多链接和额外的东西而令人困惑。
    【解决方案5】:

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

    【讨论】:

    • 我喜欢这种方法不需要 json 文件是应用程序的本地文件。谢谢!
    【解决方案6】:

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

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

    【讨论】:

    • 如果期望来自传入连接的 JSON 数据尤其如此。如果 JSON.parse 正在解析格式错误的 JSON,您的整个应用程序将会崩溃,或者使用 process.on('uncaughtException', function(err) { ... });,最终将没有机会向用户发送“格式错误的 JSON”错误。
    • async 解析器是哪一个?我没找到。
    • 链接页面现在被标记为“已弃用”,并将其自身描述为“褪色的遗物”。
    【解决方案7】:

    包括node-fs 库。

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

    有关“fs”库的更多信息,请参阅http://nodejs.org/api/fs.html 上的文档

    【讨论】:

    • 值得注意的是,您应该将 var 文件行包装在 try/catch 中,以防您的 JSON 无法解析或文件不存在。
    • 或者只是使用回调!
    【解决方案8】:

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

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

    OR 在“异步风格”

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

    【讨论】:

    • 我只想说明process.nextTick 不是aysnc。它只是推迟读取文件,直到 JS 事件循环中的下一个函数调用。要异步运行 JSON.parse,您必须使用与 Node.js 主线程不同的线程
    【解决方案9】:

    解析 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

    【讨论】:

      【解决方案10】:

      这里的每个人都谈到了 JSON.parse,所以我想说点别的。有一个很棒的模块 Connect 带有许多中间件,可以使应用程序的开发更容易和更好。其中一个中间件是bodyParser。它解析 JSON、html-forms 等。还有一个特定的中间件仅用于 JSON 解析noop

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

      【讨论】:

        【解决方案11】:
        JSON.parse("your string");
        

        就是这样。

        【讨论】:

          【解决方案12】:

          正如这里的其他答案所提到的,您可能需要一个您知道是安全且存在的本地 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

          你可以修改代码看看效果...

          【讨论】:

            【解决方案13】:

            在 Node.js 中使用 JSON 进行配置?阅读本文,让您的配置技能超过 9000...

            注意:人们声称 data = require('./data.json');是一个 安全风险和热心地拒绝人们的答案:您完全。 尝试在该文件中放置非 JSON...Node 会给你一个错误,exactly 就像你用 much 更慢更难的代码做同样的事情一样手动文件读取,然后是 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);
            }
            

            使用此模式,您现在可以在启动的应用程序上加载社区和用户配置内容,开发操作已准备好将您的工作推入容器并对其进行扩展。你读的是多租户。用户空间是孤立的。您现在可以将您正在使用的服务协议、您正在使用的数据库类型的关注点分开,并专注于编写好的代码。

            因为您使用的是层,所以您可以在任何时候(分层的配置对象)为所有事情依赖单一的事实来源,并且避免在每一步都进行错误检查,担心“哦,废话,我该怎么做让 this 在没有适当配置的情况下工作?!?”。

            【讨论】:

              【解决方案14】:

              我的解决方案:

              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 错误 - 知道从哪里开始调试此问题吗?
              【解决方案15】:

              只是想完成答案(因为我挣扎了一段时间),想展示如何访问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);
                }
              })

              【讨论】:

                【解决方案16】:

                只是为了让它尽可能复杂,并尽可能多地引入包......

                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/await:

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

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

                【讨论】:

                  【解决方案17】:

                  如果您需要使用 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
                  

                  【讨论】:

                    【解决方案18】:

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

                    来自 json-safe-parse npm 页面:

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

                    【讨论】:

                      【解决方案19】:

                      利用 Lodash 的尝试函数返回一个错误对象,您可以使用 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
                      

                      【讨论】:

                      • 你能解释一下为什么你添加了.bind 而不是仅仅使用 _.attempt(JSON.parse, str)
                      【解决方案20】:

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

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

                      【讨论】:

                        【解决方案21】:

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

                        这样使用是安全的

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

                        【讨论】:

                          【解决方案22】:

                          如果您想在 JSON 中添加一些 cmets 并允许尾随逗号,您可能需要使用以下实现:

                          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。

                          【讨论】:

                            【解决方案23】:

                            如果 JSON 源文件很大,可能需要考虑通过 Node.js 8.0 的原生 async / await 方法的异步路由,如下所示

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

                            【讨论】:

                              【解决方案24】:

                              我使用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模块的方法并承诺它们.

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

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

                              【讨论】:

                                【解决方案25】:

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

                                这里有一些例子:

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

                                【讨论】:

                                  【解决方案26】:

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

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

                                  【讨论】:

                                    【解决方案27】:

                                    为了安全起见,使用它

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

                                    【讨论】:

                                      【解决方案28】:

                                      NodeJs 是一个基于 JavaScript 的服务器,因此您可以像在纯 JavaScript 中那样做...

                                      假设你在 NodeJs 中有这个 Json...

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

                                      您可以按照上面的操作来获取您的 json 的解析版本...

                                      【讨论】:

                                        【解决方案29】:

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

                                        【讨论】:

                                          【解决方案30】:

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

                                          【讨论】:

                                          • 你看过这个问题的最佳答案吗?它已经 3 年了,非常完整。您希望在这里提供的琐碎信息中做出什么贡献?
                                          • 现在,现在,我们不要持有双重标准
                                          猜你喜欢
                                          • 1970-01-01
                                          • 2020-09-20
                                          • 2018-07-11
                                          • 1970-01-01
                                          • 1970-01-01
                                          • 1970-01-01
                                          • 1970-01-01
                                          • 1970-01-01
                                          相关资源
                                          最近更新 更多