javascript fetch - Impossible d'exécuter 'json' sur 'Response': le flux du corps est verrouillé

107

Lorsque l'état de la demande est supérieur à 400 (j'ai essayé 400, 423, 429 états), fetch ne peut pas lire le contenu json retourné. L'erreur suivante s'affiche dans la console du navigateur

Uncaught (in promise) TypeError: Impossible d'exécuter 'json' sur 'Response': le flux du corps est verrouillé

J'ai montré le contenu de l'objet de réponse retourné comme suit:

entrez la description de l'image ici

Mais je peux encore l'utiliser il y a quelques mois.

Ma question est la suivante:

  • S'agit-il uniquement du comportement du navigateur Chrome ou des modifications apportées à la norme de récupération?
  • Existe-t-il un moyen d'obtenir le contenu corporel de ces états?

PS: la version de mon navigateur est Google Chrome 70.0.3538.102 (正式 版本) (64 位)

Luna
la source
Cela signifie que vous obtenez une réponse de l'API, mais que ce n'est pas un json valide, envoyez-vous tous les paramètres requis dans la demande?
kiranvj
@kiranvj J'ai vérifié mes données, le même contenu, je viens de changer le code d'état à 200 pour l'obtenir correctement.
Luna
1
J'ai le même problème mais mon statut est 200, comment l'avez-vous résolu finalement?
DavSev
@DavSev Pour un code de statut spécifique, je reçois les données de retour via axios
Luna
1
cela arrive aussi avec 200.
schlingel

Réponses:

175

J'ai rencontré cette erreur aussi mais j'ai découvert qu'elle n'est pas liée à l'état de réponse, le vrai problème est que vous ne pouvez consommer Response.json()qu'une seule fois, si vous la consommez plus d'une fois, l'erreur se produira.

comme ci-dessous:

    fetch('http://localhost:3000/movies').then(response =>{
    console.log(response);
    if(response.ok){
         console.log(response.json()); //first consume it in console.log
        return response.json(); //then consume it again, the error happens

    }

La solution est donc d'éviter de consommer Response.json()plus d'une fois en thenbloc.

Wayne Wei
la source
5
vous pourriez response.clone()avant de le consommer.
balduran
Agréable. J'en ai eu un console.log(r.json()); return r.json();qui l'a cassé.
mewc
2
Merci, cela a fonctionné pour moi ..... quelqu'un peut-il expliquer ce comportement étrange?
Sachin le
74

Utilisation Response.clone() pour clonerResponse

exemple

fetch('yourfile.json').then(res=>res.clone().json())
Criss Colère
la source
19
Cela a très bien fonctionné pour moi, mais quelqu'un comprend pourquoi cela est nécessaire? Je l'ai recherché et je vois que parfois, une fois qu'un lecteur commence à lire Response.body, il est verrouillé sur ce lecteur. Mais d'après ce que je peux voir (du moins dans mon code), rien n'a jamais commencé à lire ... y a-t-il une explication sur la façon dont le flux lisible pourrait être automatiquement verrouillé?
jenming
5
J'ai eu le même problème mais j'ai découvert que j'avais "res.json ()" dans mon panneau de surveillance dans les outils de développement de chrome, qui était en cours de résolution avant le code lui-même!
FelipeDrumond
1
attends quoi? @FelipeDrumond c'est un (non) bug fou!
George Mauer
@GeorgeMauer Eh bien, si nous ne pouvons exécuter response.json () qu'une seule fois et que votre panneau de surveillance des outils de développement Chrome s'exécute avant votre code, vous aurez une exception parce que vous avez exécuté response.json () deux fois!
FelipeDrumond
Référence MDN
foxiris le
7

Une méthode de réponse comme «json», «text» peut être appelée une fois, puis elle se verrouille. L'image postée de la réponse montre que le corps est verrouillé. Cela signifie que vous avez déjà appelé le «alors», «attraper». Pour résoudre ce problème, vous pouvez essayer ce qui suit.

fetch(url)
    .then(response=> response.body.json())
    .then(myJson=> console.log(myJson))

Ou

fetch(url)
    .catch(response=> response.body.json())
    .catch(myJson=> console.log(myJson))
Bradia
la source
3

Je sais qu'il est trop tard mais cela peut aider quelqu'un:

let response = await fetch(targetUrl);
let data = await response.json();
chérif
la source
2

Je suis également resté là-dedans. Mais cela a fonctionné pour moi.

fetch(YOUR_URL)
.then(res => {
  try {
    if (res.ok) {
      return res.json()
    } else {
      throw new Error(res)
    }
  }
  catch (err) {
    console.log(err.message)
    return WHATEVER_YOU_WANT_TO_RETURN
  }
})
.then (resJson => {
  return resJson.data
})
.catch(err => console.log(err))

bonne chance

Ankit Kataria
la source
Un exemple de récupération dans MDN github.com/mdn/fetch-examples/blob/master/fetch-json/…
Magaesh
1

Je réutilisais accidentellement un objet de réponse, quelque chose de similaire à ceci:

const response = await new ReleasePresetStore().findAll();
const json = await response.json();
this.setState({ releasePresets: json });

const response2 = await new ReleasePresetStore().findActive();
const json2 = await response.json();
this.setState({ active: json2 });
console.log(json2);

Cette ligne:

const json2 = await response.json();

Aurait dû être (response2 au lieu de la réponse épuisée1):

const json2 = await response2.json();

Réutiliser la réponse précédente n'avait aucun sens et c'était une faute de frappe de code sale ...

Jeremy Bunn
la source
1

Cela a fonctionné pour moi

response.json().then(data => {
  // use data
})
Beau Barker
la source
0

Comme mentionné dans la question, lorsque vous essayez d'utiliser le même objet de réponse, votre corps est sur le point de se verrouiller en raison de l'état de l'objet. Ce que vous pouvez faire, c'est capturer la valeur de l'objet de réponse, puis essayer d'effectuer une opération dessus (.then ()). Veuillez suivre le code ci-dessous,

fetch('someurl').then(respose) => {
    let somedata = response.json(); // as you will capture the json response, body will not be locked anymore. 
    somedata.then(data) => {
        {
             error handling (if (data.err) { ---- })
        }
        {
             operations (else { ---- })
        }
    } 
}
Juhil Somaiya
la source