如何使用Node.js解析JSON?

时间:2011-04-20 07:10:53

标签: javascript json node.js

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

32 个答案:

答案 0 :(得分:1047)

您只需使用JSON.parse即可。

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

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

答案 1 :(得分:645)

你可以require .json文件。

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

例如,如果您在源代码文件所在的目录中有config.json文件,则可以使用:

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

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

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

请注意,require 同步,只有在 后才会读取文件 >

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

答案 2 :(得分:301)

您可以使用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. 会更容易
  4. 如果您的文件没有.json扩展名,则require不会将该文件的内容视为JSON。
  5. <强>认真!使用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调用封闭在{{1}}内。用户提供的JSON字符串可能会导致应用程序崩溃,甚至可能导致安全漏洞。如果解析外部提供的JSON,请确保完成错误处理。

答案 3 :(得分:81)

使用JSON object

JSON.parse(str);

答案 4 :(得分:33)

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

答案 5 :(得分:32)

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

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

答案 6 :(得分:29)

包含node-fs库。

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

有关&#39; fs&#39;的更多信息库,请参阅http://nodejs.org/api/fs.html

上的文档

答案 7 :(得分:9)

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

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

OR“async style”

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

答案 8 :(得分:8)

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

答案 9 :(得分: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

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

答案 10 :(得分:6)

这里的每个人都讲过JSON.parse,所以我想说点别的。有一个很棒的模块Connect,包含许多中间件,可以让应用程序的开发更容易,更好。其中一个中间件是bodyParser。它解析JSON,html表单等。还有一个特定的中间件,仅用于JSON解析noop

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

答案 11 :(得分:6)

JSON.parse("your string");

就是这样。

答案 12 :(得分:5)

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

  

注意:声称数据= require的人(&#39; ./ data.json&#39;);是一个   安全风险并以热心的热情低估了人们的答案:你完全和完全 错误 。   尝试在该文件中放置非JSON ... Node会给你一个错误,完全就像你用同样的东西做的那样很多更慢更难编码手动文件读取,然后是后续的JSON.parse()。请停止传播错误信息;你伤害了世界,没有帮助。节点设计允许这样做; 这不是安全风险!

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

  1. 服务器/容器配置
  2. 应用程序配置
  3. (可选)租户/社区/组织配置
  4. 用户配置
  5. 大多数开发人员将其服务器和应用程序配置视为可以更改。它不可能。您可以在更高层之间进行层更改,但您可以修改基本要求需要存在的一些东西!让你的配置表现得像它一样不可变,因为其中一些基本上就像你的源代码一样。

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

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

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

    <强>容器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);
    }
    

    使用此模式,您现在可以在启动的应用程序之上加载社区和用户配置,dev ops已准备好将您的工作推入容器并进行扩展。您已阅读多租户。 Userland是孤立的。您现在可以分离您正在使用的服务协议的关注点,您正在使用的数据库类型,并专注于编写优秀的代码。

    因为您正在使用图层,所以您可以随时依赖单一事实来源(分层配置对象),并避免每一步都进行错误检查,担心&#34;哦废话,如果没有正确的配置,我将如何使这个工作?!?&#34;。

答案 13 :(得分: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);
});

答案 14 :(得分:4)

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

&#13;
&#13;
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);
  }
})
&#13;
&#13;
&#13;

答案 15 :(得分: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);

或者如果您正在使用async / await:

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

仅仅使用readFileSync的优势在于节点服务器可以在从磁盘读取文件时处理其他请求。

答案 16 :(得分:2)

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

来自json-safe-parse npm页面:

  

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

答案 17 :(得分:2)

利用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

答案 18 :(得分:2)

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

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

答案 19 :(得分:1)

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

var utils = require('sdk/window/utils');
var tabs = require('sdk/tabs');
var tabsUtils = require('sdk/tabs/utils');
var self = require('sdk/self');

//For testing: Open the Browser Console
var activeWin = utils.getMostRecentBrowserWindow();
activeWin.document.getElementById('menu_browserConsole').doCommand();

var mySidebars = require('./sidebars.js');
var sidebarSize = 100;  //Width & height to use

var sidebarByWindow = false;
var sidebars = {};
//The buttons
var buttons = {
    '◀': {where:'Left'},
    '▶': {where:'Right'},
    '▲': {where:'Top'},
    '▼': {where:'Bottom'},
    '☐': {where:'Window'}
};

//Create Buttons
var sdkActionButtons     = require('sdk/ui/button/action');

for(let badge in buttons){
    buttons[badge].button = sdkActionButtons.ActionButton({
        id: 'openSidebar' + buttons[badge].where,
        label: 'Open ' + buttons[badge].where + ' Sidebar',
        badge: badge,
        badgeColor: 'green',
        icon: './icons/Aurora-icon64.png',
        onClick: handleButtonClick
    });
}

function handleButtonClick(state){
    let where = buttons[state.badge].where.toLowerCase();
    let stateType = getSidebarByWindowText();
    let sidebarId = getSidebarId(state.badge,sidebarByWindow);
    //With this state being kept by window and tab, the checked property does
    //  not accurately track what we need to be doing, so use badgeColor and
    //  action buttons.
    if(sidebars[sidebarId]){
        //If we have a sidebar for this combo, then
        let elements = sidebars[sidebarId];
        if(elements){
            if(where==='window'){
                try{
                    elements[0].close();
                }catch(e){
                    //Do nothing. We should be tracking the state of the window so
                    //  users can use the close button. We are not, so trying to
                    //  close an already closed window could throw an error.
                }
            } else {
                elements.forEach(el => {el.remove();});
            }
        }
        delete sidebars[sidebarId];
    }else{
        //Create the sidebar and keep track of it so it can be removed.
        sidebars[sidebarId] = mySidebars.createInterfacePanelIframe(where,{
            url:self.data.url('sidebar.html'),
            byWindow:sidebarByWindow,
            size:sidebarSize,
            id:'makyen-interface-panel-' + stateType + '- ' + where
        });
        //Make the text reflect the sidebar
        if(where !== 'window'){
            setBodyText(sidebarId, 'This is a ' +stateType + ' ' + where + ' Sidebar.');
            sidebars[sidebarId][1].addEventListener('load', setBodyText.bind(null
                ,sidebarId
                ,'This is a ' + stateType.toUpperCase() + ' ' + where + ' Sidebar.'),true);
        }
    }
    updateButtonBadgeColors();
}

function setBodyText(sidebarId,text){
    let doc = sidebars[sidebarId][1].contentDocument; 
    doc.body.textContent = text;
}

function getSidebarId(badge,sidebarByWindow,domWin){
    let where = buttons[badge].where.toLowerCase();
    let stateType = getSidebarByWindowText();
    domWin = domWin?domWin:utils.getMostRecentBrowserWindow();
    let winId = utils.getOuterId(domWin);
    //This should get the tab ID from any window, not just the active window.
    let tabId = tabsUtils.getTabId(tabsUtils.getActiveTab(domWin));
    let id = sidebarByWindow?winId:tabId;
    return stateType+id+where;
}

function getSidebarByWindowText(){
    return sidebarByWindow?'window':'tab';
}

function updateButtonBadgeColors(){
    //Update the badge colors in all windows based on if there is a sidebar of the
    //  current type for the window/tab.
    let allWindows = utils.windows('navigator:browser',{includePrivate:true});
    for(let win of allWindows){
        for(let badge in buttons){
            let sidebarId = getSidebarId(badge,sidebarByWindow,win);
            buttons[badge].button.state(win,{
                badgeColor : sidebars[sidebarId]?'red':'green'
            });
        }
    }
}
//update badge colors each time the active tab changes.
tabs.on('activate',updateButtonBadgeColors);

//var sdkToggleButtons     = require('sdk/ui/button/toggle');
var windowTabLabelText = 'Sidebars are associated with ';
var windowTabToggleButton = sdkActionButtons.ActionButton({
    id: 'windowTabToggleButton',
    label: windowTabLabelText + getSidebarByWindowText(),
    icon: './icons/Aurora-icon64.png',
    onClick: handlewindowTabToggle
});

function handlewindowTabToggle(state){
    if(!state.badge){
        windowTabToggleButton.badge= '☐';
        windowTabToggleButton.badgeColor= 'blue';
        sidebarByWindow = true;
    } else {
        windowTabToggleButton.badge= '';
        sidebarByWindow = false;
    }
    windowTabToggleButton.label = windowTabLabelText + getSidebarByWindowText();
    updateButtonBadgeColors();
}

请注意,如果您的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); } 之类的内容,则可能效果不佳。所以YMMV。

答案 20 :(得分: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的方法。模块并使其合理化。

  

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

的注释

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

答案 21 :(得分: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))

答案 22 :(得分:0)

如果您需要以安全的方式(例如:用户可以输入数据或公共API)使用Node.js解析JSON,我建议使用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

答案 23 :(得分: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")
}

答案 24 :(得分:0)

NodeJs 是基于 JavaScript 的服务器,因此您可以使用纯 JavaScript ...

想象一下,您在 NodeJs ...

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

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

答案 25 :(得分:0)

使用它是为了安全起见

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

答案 26 :(得分:0)

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

或者使用一些JSON解析npm库,类似于vue-generate-component

答案 27 :(得分:-1)

使用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

答案 28 :(得分:-1)

无需其他模块。
只需使用
{{1}}
我认为这个

存在任何安全问题

答案 29 :(得分:-2)

这必须对我大喊:它只适用于.json个文件。

如果文件结尾不同,则不起作用!

答案 30 :(得分:-2)

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

答案 31 :(得分:-3)

var fs = require('fs');

fs.readFile('ashish.json',{encoding:'utf8'},function(data,err) {

   if(err) 
      throw err;

   else {

   console.log(data.toString());

 }
})