Як повернути складну відповідь JSON за допомогою Node.js?


82

Використовуючи nodejs і express, я хотів би повернути один або кілька об’єктів (масив) за допомогою JSON. У наведеному нижче коді я вивожу по одному об'єкту JSON за раз. Це працює, але це не зовсім те, що я хочу. Вироблена відповідь не є дійсною відповіддю JSON, оскільки у мене багато об’єктів.

Я добре знаю, що я міг би просто додати всі об'єкти до масиву і повернути цей конкретний масив у res.end. Однак я боюся, що це може стати важким для обробки та інтенсивної пам'яті.

Який правильний спосіб досягти цього за допомогою nodejs? Чи є query.each правильним методом для виклику?

app.get('/users/:email/messages/unread', function(req, res, next) {
    var query = MessageInfo
        .find({ $and: [ { 'email': req.params.email }, { 'hasBeenRead': false } ] });

    res.writeHead(200, { 'Content-Type': 'application/json' });   
    query.each(function(err, msg) {
        if (msg) { 
            res.write(JSON.stringify({ msgId: msg.fileName }));
        } else {
            res.end();
        }
    });
});

Відповіді:


183

На Express 3 ви можете використовувати безпосередньо res.json ({foo: bar})

res.json({ msgId: msg.fileName })

Дивіться документацію


9
як це зробити без експресу?
Піотрек,

@ Людвік11 res.write(JSON.stringify(foo)). Якщо fooвелике, вам, можливо, доведеться його подрібнити (stringify, а потім писати шматки за раз). Можливо, ви також хочете побачити ваш заголовок "Content-Type":"application/json"або подібний за необхідністю.
OJFord,

21

Я не знаю, чи насправді це інакше, але замість того, щоб перебирати курсор запиту, ви можете зробити щось подібне:

query.exec(function (err, results){
  if (err) res.writeHead(500, err.message)
  else if (!results.length) res.writeHead(404);
  else {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.write(JSON.stringify(results.map(function (msg){ return {msgId: msg.fileName}; })));
  }
  res.end();
});

12

[Редагувати] Після перегляду документації Mongoose, схоже, ви можете надіслати кожен результат запиту як окремий шматок; веб-сервер використовує кодоване кодування передачі за замовчуванням, тому все, що вам потрібно зробити, це обернути масив навколо елементів, щоб зробити його дійсним об'єктом JSON.

Приблизно (неперевірений):

app.get('/users/:email/messages/unread', function(req, res, next) {
  var firstItem=true, query=MessageInfo.find(/*...*/);
  res.writeHead(200, {'Content-Type': 'application/json'});
  query.each(function(docs) {
    // Start the JSON array or separate the next element.
    res.write(firstItem ? (firstItem=false,'[') : ',');
    res.write(JSON.stringify({ msgId: msg.fileName }));
  });
  res.end(']'); // End the JSON array and response.
});

Як варіант, як ви вже згадували, ви можете просто надіслати вміст масиву як є. У цьому випадку тіло відповіді буферизується і негайно надсилається, що може споживати велику кількість додаткової пам'яті (вище того, що потрібно для зберігання самих результатів) для великих наборів результатів. Наприклад:

// ...
var query = MessageInfo.find(/*...*/);
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(query.map(function(x){ return x.fileName })));

Це гарна ідея. Однак для мене це виглядає дещо шалено. Я сподівався, що nodejs запропонує щось більш елегантне.
Мартін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.