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?

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ć.


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

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

10
Co to jest fs, co to jest pipe, co jest czytelne? Twoja odpowiedź jest bardziej tajemnicza
Aakash Dave


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

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


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
    }
      ]
}

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

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.


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

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.