Правильный способ вернуть JSON с помощью узла или Express


440

Итак, можно попытаться получить следующий объект JSON:

$ curl -i -X GET http://echo.jsontest.com/key/value/anotherKey/anotherValue
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=ISO-8859-1
Date: Wed, 30 Oct 2013 22:19:10 GMT
Server: Google Frontend
Cache-Control: private
Alternate-Protocol: 80:quic,80:quic
Transfer-Encoding: chunked

{
   "anotherKey": "anotherValue",
   "key": "value"
}
$

Есть ли способ получить точно такое же тело в ответе от сервера, используя узел или экспресс? Ясно, что можно установить заголовки и указать, что тип содержимого ответа будет «application / json», но тогда есть разные способы записи / отправки объекта. То, что я часто видел, используется командой вида:

response.write(JSON.stringify(anObject));

Однако в этом есть два момента, в которых можно утверждать, что это были «проблемы»:

  • Мы отправляем строку.
  • Более того, в конце нет символа новой строки.

Другая идея заключается в использовании команды:

response.send(anObject);

Похоже, что это отправка объекта JSON на основе вывода curl, как в первом примере выше. Тем не менее, нет символа новой строки в конце тела, когда curl снова используется на терминале. Итак, как можно на самом деле записать что-то вроде этого с символом новой строки, добавляемым в конце, используя узел или узел / экспресс?

Ответы:


620

Этот ответ также является строкой, если вы хотите отправить ответ предварительно, по какой-то неловкой причине, вы можете использовать что-то вроде JSON.stringify(anObject, null, 3)

Важно также установить Content-Typeзаголовок application/json.

var http = require('http');

var app = http.createServer(function(req,res){
    res.setHeader('Content-Type', 'application/json');
    res.end(JSON.stringify({ a: 1 }));
});
app.listen(3000);

// > {"a":1}

Prettified:

var http = require('http');

var app = http.createServer(function(req,res){
    res.setHeader('Content-Type', 'application/json');
    res.end(JSON.stringify({ a: 1 }, null, 3));
});
app.listen(3000);

// >  {
// >     "a": 1
// >  }

Я не совсем уверен, почему вы хотите прекратить это с новой строкой, но вы могли бы просто сделать JSON.stringify(...) + '\n'это.

Экспресс

В экспрессе вы можете сделать это, изменив параметры .

'json replacer' Обратный вызов заменителя JSON, по умолчанию null

'json spaces' Пространства ответов JSON для форматирования, по умолчанию 2 в разработке, 0 в производстве

На самом деле не рекомендуется устанавливать до 40

app.set('json spaces', 40);

Тогда вы можете просто ответить с JSON.

res.json({ a: 1 });

Он будет использовать 'json spaces«конфигурацию», чтобы предварительно подтвердить его.


3
Спасибо за ваше время. Если честно, у меня нет проблем с моей стороны. Просто кто-то (в другом часовом поясе) жаловался на формат, который я использовал, потому что он хотел получить, и по какой-то причине они не могли правильно прочитать мой объект. Спасибо, что отметили хорошую версию stringify. :)
MightyMouse

2
Этот кто-то должен действительно разбирать строку JSON на объекты или использовать расширение браузера , а не пытаться делать какое-либо чтение вручную.
Bevacqua

2
@akshay Еще лучше, res.sendавтоматически установит content-typeдля JSON, если отправленный элемент является объектом или массивом.
Royhowie

3
Я думаю, что вы хотели использовать res.end()в своем http(
неэкспресс

2
@ ТобиасФюнке прав, я думаю. res.send()не работает. Пожалуйста, исправьте это, если это ошибка. res.end()работает правильно. Спасибо, кстати.
Kaushal28

410

Начиная с Express.js 3x, объект ответа имеет метод json (), который корректно устанавливает все заголовки и возвращает ответ в формате JSON.

Пример:

res.json({"foo": "bar"});

Спасибо за ваше время. Однако тогда мой вопрос был не совсем о заголовках. Это было больше о результате, который можно увидеть, скажем, через завиток. Еще раз спасибо.
MightyMouse

53
Хорошо, но этот метод также возвращает правильно отформатированный JSON. Это часть ответа. Поэтому res.json () устанавливает правильные заголовки, а затем JSON.stringify () автоматически отвечает за вас.
JamieL

19

Если вы пытаетесь отправить файл JSON, вы можете использовать потоки

var usersFilePath = path.join(__dirname, 'users.min.json');

apiRouter.get('/users', function(req, res){
    var readable = fs.createReadStream(usersFilePath);
    readable.pipe(res);
});

10
Что такое fs, что такое pipe, что читается? Ваш ответ более загадочный
Аакаш Дейв

11

res.json()Функция должна быть достаточна для большинства случаев.

app.get('/', (req, res) => res.json({ answer: 42 }));

В res.json()функции преобразует параметр вы передаете JSON с помощью JSON.stringify()и задает Content-Typeзаголовок к application/json; charset=utf-8таким HTTP клиенты знают , автоматически разобрать ответ.


6

если вы используете Express, вы можете использовать это:

res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({key:"value"}));

или только это

res.json({key:"value"});

5

Вы можете просто настроить его, используя pipe и один из многих процессоров. Ваше приложение должно всегда отвечать с как можно меньшей нагрузкой.

$ curl -i -X GET http://echo.jsontest.com/key/value/anotherKey/anotherValue | underscore print

https://github.com/ddopson/underscore-cli


4

Для этого вы можете создать вспомогательный инструмент: создать вспомогательную функцию, чтобы вы могли использовать ее везде в своем приложении.

function getStandardResponse(status,message,data){
    return {
        status: status,
        message : message,
        data : data
     }
}

Вот мой маршрут темы, где я пытаюсь получить все темы

router.get('/', async (req, res) => {
    const topics = await Topic.find().sort('name');
    return res.json(getStandardResponse(true, "", topics));
});

Ответ мы получаем

{
"status": true,
"message": "",
"data": [
    {
        "description": "sqswqswqs",
        "timestamp": "2019-11-29T12:46:21.633Z",
        "_id": "5de1131d8f7be5395080f7b9",
        "name": "topics test xqxq",
        "thumbnail": "waterfall-or-agile-inforgraphics-thumbnail-1575031579309.jpg",
        "category_id": "5de0fe0b4f76c22ebce2b70a",
        "__v": 0
    },
    {
        "description": "sqswqswqs",
        "timestamp": "2019-11-29T12:50:35.627Z",
        "_id": "5de1141bc902041b58377218",
        "name": "topics test xqxq",
        "thumbnail": "waterfall-or-agile-inforgraphics-thumbnail-1575031835605.jpg",
        "category_id": "5de0fe0b4f76c22ebce2b70a",
        "__v": 0
    },
    {
        "description": " ",
        "timestamp": "2019-11-30T06:51:18.936Z",
        "_id": "5de211665c3f2c26c00fe64f",
        "name": "topics test xqxq",
        "thumbnail": "waterfall-or-agile-inforgraphics-thumbnail-1575096678917.jpg",
        "category_id": "5de0fe0b4f76c22ebce2b70a",
        "__v": 0
    },
    {
        "description": "null",
        "timestamp": "2019-11-30T06:51:41.060Z",
        "_id": "5de2117d5c3f2c26c00fe650",
        "name": "topics test xqxq",
        "thumbnail": "waterfall-or-agile-inforgraphics-thumbnail-1575096701051.jpg",
        "category_id": "5de0fe0b4f76c22ebce2b70a",
        "__v": 0
    },
    {
        "description": "swqdwqd wwwwdwq",
        "timestamp": "2019-11-30T07:05:22.398Z",
        "_id": "5de214b2964be62d78358f87",
        "name": "topics test xqxq",
        "thumbnail": "waterfall-or-agile-inforgraphics-thumbnail-1575097522372.jpg",
        "category_id": "5de0fe0b4f76c22ebce2b70a",
        "__v": 0
    },
    {
        "description": "swqdwqd wwwwdwq",
        "timestamp": "2019-11-30T07:36:48.894Z",
        "_id": "5de21c1006f2b81790276f6a",
        "name": "topics test xqxq",
        "thumbnail": "waterfall-or-agile-inforgraphics-thumbnail-1575099408870.jpg",
        "category_id": "5de0fe0b4f76c22ebce2b70a",
        "__v": 0
    }
      ]
}

3

Вы можете использовать промежуточное программное обеспечение, чтобы установить тип контента по умолчанию и установить тип контента по-разному для определенных API. Вот пример:

const express = require('express');
const app = express();

const port = process.env.PORT || 3000;

const server = app.listen(port);

server.timeout = 1000 * 60 * 10; // 10 minutes

// Use middleware to set the default Content-Type
app.use(function (req, res, next) {
    res.header('Content-Type', 'application/json');
    next();
});

app.get('/api/endpoint1', (req, res) => {
    res.send(JSON.stringify({value: 1}));
})

app.get('/api/endpoint2', (req, res) => {
    // Set Content-Type differently for this particular API
    res.set({'Content-Type': 'application/xml'});
    res.send(`<note>
        <to>Tove</to>
        <from>Jani</from>
        <heading>Reminder</heading>
        <body>Don't forget me this weekend!</body>
        </note>`);
})

2

Для заголовка половины вопроса, я дам пару слов res.typeздесь:

res.type('json')

эквивалентно

res.setHeader('Content-Type', 'application/json')

Источник: экспресс документы :

Устанавливает HTTP-заголовок Content-Type для типа MIME, как определено mime.lookup () для указанного типа. Если тип содержит символ «/», он устанавливает тип содержимого для типа.


1

Старая версия Express используется app.use(express.json())или bodyParser.json() читайте больше о промежуточном программном обеспечении bodyParser

На последней версии экспресса мы могли бы просто использовать res.json()

const express = require('express'),
    port = process.env.port || 3000,
    app = express()

app.get('/', (req, res) => res.json({key: "value"}))

app.listen(port, () => console.log(`Server start at ${port}`))

Дорогой мой, ты путаешь ответ с запросом. Промежуточное программное обеспечение BodyParser предназначено для синтаксического анализа запроса и req.bodyявляется объектом, отправляемым как тело запроса.
Матиас Гринишак
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.