Właściwy sposób zwrotu JSON przy użyciu węzła lub Express

440

Można więc spróbować pobrać następujący obiekt 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"
}
$

Czy istnieje sposób na utworzenie dokładnie tego samego ciała w odpowiedzi z serwera używającego węzła lub ekspresowego? Oczywiście można ustawić nagłówki i wskazać, że typem odpowiedzi będzie „application / json”, ale istnieją różne sposoby pisania / wysyłania obiektu. Ten, który często widziałem, jest używany za pomocą polecenia formularza:

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

Ma to jednak dwa punkty, w których można argumentować, jakby to były „problemy”:

  • Wysyłamy ciąg.
  • Ponadto na końcu nie ma nowego znaku linii.

Innym pomysłem jest użycie polecenia:

response.send(anObject);

Wygląda na to, że wysyła obiekt JSON na podstawie danych wyjściowych curl podobny do pierwszego przykładu powyżej. Jednak na końcu treści nie ma nowego znaku linii, gdy zawinięcie jest ponownie używane na terminalu. Jak zatem można zapisać coś takiego, dodając na końcu nowy znak linii za pomocą węzła lub węzła / ekspresu?

MightyMouse
źródło

Odpowiedzi:

620

Ta odpowiedź również jest ciągiem, jeśli chcesz wysłać odpowiedź z pretekstem, z jakiegoś niezręcznego powodu, możesz użyć czegoś takiego JSON.stringify(anObject, null, 3)

Ważne jest, aby również ustawić Content-Typenagłówek 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
// >  }

Nie jestem do końca pewien, dlaczego chcesz zakończyć to nową linią, ale możesz po prostu to zrobić JSON.stringify(...) + '\n'.

Wyrazić

W trybie ekspresowym możesz to zrobić, zmieniając opcje zamiast tego .

'json replacer' Oddzwanianie zamiennika JSON, domyślnie null

'json spaces' Przestrzenie odpowiedzi JSON dla formatowania, domyślnie 2 w fazie rozwoju, 0 w fazie produkcji

W rzeczywistości nie zaleca się ustawiania na 40

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

Wtedy możesz po prostu odpowiedzieć jakimś jsonem.

res.json({ a: 1 });

To będzie używać 'json spaces"konfiguracji, aby je upiększać.

bevacqua
źródło
3
Dziękuję za Twój czas. Szczerze mówiąc, nie mam problemu po mojej stronie. Po prostu ktoś (w innej strefie czasowej) narzekał na format, którego używałem, ponieważ chciał uzyskać i z jakiegoś powodu nie mógł poprawnie odczytać mojego obiektu. Dzięki za zwrócenie uwagi na fajną wersję stringify. :)
MightyMouse
2
Ten ktoś powinien naprawdę przetwarzać ciąg JSON na obiekty lub używać rozszerzenia przeglądarki , zamiast próbować czytać ręcznie.
bevacqua
2
@akshay Nawet lepiej, res.sendautomatycznie ustawi content-typeJSON, jeśli wysłany element jest obiektem lub tablicą.
royhowie
3
Myślę, że chciałeś użyć res.end()w swoim http(nie ekspresowym) przykładzie
Tobias Fünke
2
@ TobiasFünke ma rację, myślę. res.send()nie działa. Popraw to, jeśli jest to pomyłka. res.end()działa poprawnie. Dziękuję btw.
Kaushal28,
410

Od Express.js 3x obiekt odpowiedzi ma metodę json (), która ustawia poprawnie wszystkie nagłówki i zwraca odpowiedź w formacie JSON.

Przykład:

res.json({"foo": "bar"});
JamieL
źródło
Dziękuję za Twój czas. Jednak moje pytanie tak naprawdę nie dotyczyło wtedy nagłówków. Chodziło bardziej o wynik, który można było powiedzieć poprzez zwijanie. W każdym razie jeszcze raz dziękuję.
MightyMouse
53
OK, ale ta metoda zwraca również poprawnie sformatowany JSON. Jest to część odpowiedzi. Więc res.json () ustawia poprawne nagłówki, a następnie JSON.stringify () automatycznie odpowiada za Ciebie.
JamieL,
19

Jeśli próbujesz wysłać plik Json, możesz użyć strumieni

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

apiRouter.get('/users', function(req, res){
    var readable = fs.createReadStream(usersFilePath);
    readable.pipe(res);
});
Connor Leech
źródło
10
Co to jest fs, co to jest pipe, co jest czytelne? Twoja odpowiedź jest bardziej tajemnicza
Aakash Dave
11

res.json()Funkcja powinna być wystarczająca dla większości przypadków.

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

W res.json()nawróceni funkcyjne parametr przekazać do JSON użyciu JSON.stringify()i ustawia Content-Typenagłówek do application/json; charset=utf-8tak HTTP klienci wiedzą, do automatycznego analizowania odpowiedzi.

vkarpov15
źródło
6

jeśli używasz Express, możesz użyć tego:

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

lub po prostu to

res.json({key:"value"});
IXOVER
źródło
5

Możesz go upiększyć za pomocą potoku i jednego z wielu procesorów. Twoja aplikacja powinna zawsze reagować przy jak najmniejszym obciążeniu.

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

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

pawelzny
źródło
4

Możesz w tym celu stworzyć pomocnika: utwórz funkcję pomocnika, abyś mógł z niej korzystać wszędzie w swojej aplikacji

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

Oto moja ścieżka tematyczna, w której próbuję uzyskać wszystkie tematy

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

Otrzymujemy odpowiedź

{
"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
    }
      ]
}
Nishant
źródło
3

Można użyć oprogramowania pośredniego, aby ustawić domyślny typ zawartości i ustawić inaczej typ zawartości dla poszczególnych interfejsów API. Oto przykład:

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>`);
})
Yuci
źródło
2

Jeśli chodzi o nagłówek w połowie pytania, wykrzyknę res.typetutaj:

res.type('json')

jest równa

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

Źródło: express docs :

Ustawia nagłówek HTTP Content-Type na typ MIME określony przez mime.lookup () dla określonego typu. Jeśli typ zawiera znak „/”, wówczas ustawia typ zawartości na typ.

MalcolmOcean
źródło
1

Starsza wersja Express używa app.use(express.json())lub bodyParser.json() przeczytaj więcej o oprogramowaniu pośrednim bodyParser

W najnowszej wersji ekspresu moglibyśmy po prostu użyć 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}`))
Aung Zan Baw
źródło
Moja droga, mylisz odpowiedź z prośbą. Oprogramowanie pośrednie BodyParser służy do analizowania żądania, dzięki czemu req.bodyobiekt jest wysyłany jako treść żądania.
Matthias Hryniszak