Comment vérifier si la réponse d'une extraction est un objet json en javascript

94

J'utilise fetch polyfill pour récupérer un JSON ou du texte à partir d'une URL, je veux savoir comment puis-je vérifier si la réponse est un objet JSON ou s'il s'agit uniquement de texte

fetch(URL, options).then(response => {
   // how to check if response has a body of type json?
   if (response.isJson()) return response.json();
});
Sibelius Seraphini
la source

Réponses:

162

Vous pouvez vérifier le content-typede la réponse, comme indiqué dans cet exemple 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
    });
  }
});

Si vous devez être absolument sûr que le contenu est un JSON valide (et ne pas faire confiance aux en-têtes), vous pouvez toujours accepter la réponse en tant que textet l'analyser vous-même:

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

Asynchroniser / attendre

Si vous utilisez async/await, vous pouvez l'écrire de manière plus linéaire:

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
  }
}
nils
la source
1
Avec la même stratégie, vous pouvez simplement utiliser response.json en combinaison avec catch; si vous attrapez une erreur, cela signifie que ce n'est pas json. Ne serait-ce pas une manière plus idiomatique de gérer cela (au lieu d'abandonner response.json)?
Wouter Ronteltap
3
@WouterRonteltap: N'êtes-vous pas seulement autorisé à faire l'un ou l'autre. Il semble que je me souvienne que vous n'obtenez qu'une seule chance sur response.anything (). Si tel est le cas, JSON est du texte, mais le texte n'est pas nécessairement JSON. Par conséquent, vous devez d'abord faire la chose sûre, qui est .text (). Si vous faites d'abord .json () et que cela échoue, je ne pense pas que vous aurez l'opportunité de faire également .text (). Si je me trompe, veuillez me montrer différent.
Lonnie Best
2
À mon avis, vous ne pouvez pas faire confiance aux en-têtes (même si vous le devriez, mais parfois vous ne pouvez tout simplement pas contrôler le serveur de l'autre côté). C'est donc formidable que vous mentionniez également la capture d'essai dans votre réponse.
Jacob
2
Oui, @Lonnie Best a tout à fait raison. si vous appelez .json () et qu'il lève une exception (parce que la réponse n'est pas json), vous obtiendrez une exception "Body a déjà été consommé" si vous appelez par la suite .text ()
Andy
1

Utilisez un analyseur JSON comme 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
la source
1

Vous pouvez le faire proprement avec une fonction d'assistance:

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

Et puis utilisez-le comme ceci:

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

Cela générera une erreur afin que vous puissiez le catchfaire si vous le souhaitez.

Larskarbo
la source