javascript fetch-「応答」で「json」を実行できませんでした:ボディストリームがロックされています


107

リクエストのステータスが400より大きい場合(400、423、429の状態を試しました)、フェッチは返されたjsonコンテンツを読み取ることができません。ブラウザコンソールに次のエラーが表示されます

Uncaught(in promise)TypeError: 'json' on 'Response':Failed to body stream is locked

返された応答オブジェクトの内容を次のように示しました。

ここに画像の説明を入力してください

しかし、私はまだ数ヶ月前にそれを使用できます。

私の質問は次のとおりです:

  • これはChromeブラウザの動作ですか、それともフェッチ標準の変更ですか?
  • これらの状態の本文コンテンツを取得する方法はありますか?

PS:私のブラウザーのバージョンはGoogle Chrome 70.0.3538.102(正式版本)(64位)です


これは、APIからの応答を取得しているが、有効なjsonではないことを意味します。要求ですべての必須パラメーターを送信していますか?
kiranvj 2018年

@kiranvjデータを確認しましたが、同じコンテンツです。ステータスコードを200に変更して、正しく取得しました。
ルナ

1
同じ問題がありますが、ステータスは200ですが、最終的にどのように解決しましたか?
DavSev 2018

@DavSev特定のステータスコードの場合、axiosを介して戻りデータを取得します
Luna

1
200でも発生します。
シュリンゲル

回答:


175

私もこのエラーに遭遇しましたが、それはResponseの状態とは関係がないことがわかりました。本当の問題は、Response.json()1度しか消費できないことです。複数回消費すると、エラーが発生します。

以下のように:

    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

    }

したがって、解決策はResponse.json()thenブロック内で複数回消費することを避けることです。


5
あなたはresponse.clone()それを消費する前にできます。
バルドゥラン

いいね。私はconsole.log(r.json()); return r.json();それを壊しました。
mewc

2
おかげで私にとってはうまくいった.....誰かがこの奇妙な行動を説明できますか?
Sachin

74

Response.clone()複製に使用Response

fetch('yourfile.json').then(res=>res.clone().json())

19
これは私にとってはうまくいきましたが、なぜこれが必要なのか誰でも理解できますか?調べたところ、リーダーがを読み始めるResponse.bodyと、そのリーダーにロックされることがあります。しかし、私が見ることができるものから(少なくとも私のコードでは)、何も読んだことがありません...読み取り可能なストリームが自動的にロックされる方法の説明はありますか?
1

5
私は同じ問題を抱えていましたが、クロム開発ツールのウォッチパネルに「res.json()」があり、コード自体の前に解決されていました。
FelipeDrumond

1
待って、何?@FelipeDrumondはクレイジーな(非)バグです!
George Mauer

@GeorgeMauerまあ、response.json()を1回しか実行できず、Chrome開発ツールのウォッチパネルがコードの前に実行する場合は、response.json()を2回実行したため、例外が発生します。
FelipeDrumond

参照MDN
foxiris

7

「json」、「text」などの応答メソッドは一度だけ呼び出すとロックされます。投稿されたレスポンスの画像は、ボディがロックされていることを示しています。これは、「then」、「catch」をすでに呼び出していることを意味します。これを愛するためにあなたは以下を試すことができます。

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

または

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

3

手遅れだと知っていますが、誰かを助けることができます:

let response = await fetch(targetUrl);
let data = await response.json();


1

次のような応答オブジェクトを誤って再利用していました。

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

この行:

const json2 = await response.json();

あったはずです(使いきったresponse1の代わりにresponse2):

const json2 = await response2.json();

以前の応答を再利用しても意味がなく、汚いコードのタイプミスでした...



0

同じ応答オブジェクトを使用しようとしたときの質問で述べたように、オブジェクトの状態が原因でボディがロックされようとしています。あなたができることは、応答オブジェクトの値を取得し、それに対して何らかの操作を試みることです(.then())。以下のコードに従ってください、

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 { ---- })
        }
    } 
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.