Jak sprawdzić, czy odpowiedź pobierania jest obiektem json w javascript

100

Używam fetch polyfill, aby pobrać JSON lub tekst z adresu URL, chcę wiedzieć, jak mogę sprawdzić, czy odpowiedź jest obiektem JSON, czy jest to tylko tekst

fetch(URL, options).then(response => {
   // how to check if response has a body of type json?
   if (response.isJson()) return response.json();
});
Sibelius Seraphini
źródło

Odpowiedzi:

175

Możesz sprawdzić content-typeodpowiedź, jak pokazano w tym przykładzie MDN :

fetch(myRequest).then(response => {
  const contentType = response.headers.get("content-type");
  if (contentType && contentType.indexOf("application/json") !== -1) {
    return response.json().then(data => {
      // process your JSON data further
    });
  } else {
    return response.text().then(text => {
      // this is text, do something with it
    });
  }
});

Jeśli chcesz mieć absolutną pewność, że zawartość jest poprawna w formacie JSON (i nie ufasz nagłówkom), zawsze możesz po prostu zaakceptować odpowiedź jako texti samodzielnie ją przeanalizować:

fetch(myRequest)
  .then(response => response.text())
  .then(text => {
    try {
        const data = JSON.parse(text);
        // Do your JSON handling here
    } catch(err) {
       // It is text, do you text handling here
    }
  });

Async / await

Jeśli używasz async/await, możesz napisać to w bardziej liniowy sposób:

async function myFetch(myRequest) {
  try {
    const reponse = await fetch(myRequest); // Fetch the resource
    const text = await response.text(); // Parse it as text
    const data = JSON.parse(text); // Try to parse it as json
    // Do your JSON handling here
  } catch(err) {
    // This probably means your response is text, do you text handling here
  }
}
zero
źródło
1
Dzięki tej samej strategii możesz po prostu użyć response.json w połączeniu z catch; jeśli złapiesz błąd, oznacza to, że nie jest to json. Czy nie byłby to bardziej idiomatyczny sposób radzenia sobie z tym (zamiast rezygnacji z response.json)?
Wouter Ronteltap
3
@WouterRonteltap: Czy nie wolno ci robić tylko jednego lub drugiego. Wygląda na to, że pamiętam, że masz tylko jedną szansę na odpowiedź. Cokolwiek (). Jeśli tak, JSON jest tekstem, ale tekst niekoniecznie jest JSON. Dlatego musisz najpierw zrobić pewną rzecz, czyli .text (). Jeśli najpierw zrobisz .json () i nie powiedzie się, nie sądzę, że będziesz miał okazję również zrobić .text (). Jeśli się mylę, pokaż mi coś innego.
Lonnie Best
2
Moim zdaniem nie możesz ufać nagłówkom (chociaż powinieneś, ale czasami po prostu nie możesz kontrolować serwera po drugiej stronie). Więc wspaniale, że w swojej odpowiedzi wspomniałeś również o próbowaniu łapania.
Jacob
2
Tak, @Lonnie Best jest w tym całkowicie poprawny. jeśli wywołasz .json () i zgłosi wyjątek (ponieważ odpowiedź nie jest json), otrzymasz wyjątek „Treść została już skonsumowana”, jeśli następnie wywołasz .text ()
Andy
3

Możesz to zrobić czysto za pomocą funkcji pomocniczej:

const parseJson = async response => {
  const text = await response.text()
  try{
    const json = JSON.parse(text)
    return json
  } catch(err) {
    throw new Error("Did not receive JSON, instead received: " + text)
  }
}

A potem użyj tego w ten sposób:

fetch(URL, options)
.then(parseJson)
.then(result => {
    console.log("My json: ", result)
})

Spowoduje to wyświetlenie błędu, więc możesz catchto zrobić, jeśli chcesz.

larskarbo
źródło
1

Użyj parsera JSON, takiego jak JSON.parse:

function IsJsonString(str) {
    try {
        var obj = JSON.parse(str);

         // More strict checking     
         // if (obj && typeof obj === "object") {
         //    return true;
         // }

    } catch (e) {
        return false;
    }
    return true;
}
Rakesh Soni
źródło