fetch() の概要

fetch() API は window オブジェクトで XHR の置き換えを検討しています

長い XMLHttpRequest

fetch() を使用すると、XMLHttpRequest(XHR)と同様のネットワーク リクエストを行うことができます。主な違いは、Fetch API では Promise を使用する点です。これにより、よりシンプルでクリーンな API が有効になり、コールバックの地獄が回避され、XMLHttpRequest の複雑な API を記憶する必要がなくなります。

対応ブラウザ

  • 42
  • 14
  • 39
  • 10.1

ソース

Fetch API は Chrome 40 以降、Service Worker グローバル スコープで使用できますが、Chrome 42 ではウィンドウ スコープで有効になる予定です。現在使用できる、比較的取得性の高い GitHub によるポリフィルもあります。

Promise を初めて使用する場合は、JavaScript Promise の概要をご覧ください。

基本的な取得リクエスト

まず、XMLHttpRequest で実装され、次に fetch で実装された簡単な例を比較してみましょう。URL をリクエストしてレスポンスを取得して JSON として解析すればよいだけです

XMLHttpRequest

XMLHttpRequest には、成功ケースとエラーケースを処理するために 2 つのリスナー、および open()send() の呼び出しを設定する必要があります。MDN ドキュメントの例

function reqListener() {
    var data = JSON.parse(this.responseText);
    console.log(data);
}

function reqError(err) {
    console.log('Fetch Error :-S', err);
}

var oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.onerror = reqError;
oReq.open('get', './api/some.json', true);
oReq.send();

フェッチ

取得リクエストは次のようになります。

fetch('./api/some.json')
    .then(
    function(response) {
        if (response.status !== 200) {
        console.log('Looks like there was a problem. Status Code: ' +
            response.status);
        return;
        }

        // Examine the text in the response
        response.json().then(function(data) {
        console.log(data);
        });
    }
    )
    .catch(function(err) {
    console.log('Fetch Error :-S', err);
    });

レスポンスを JSON として解析する前に、レスポンス ステータスが 200 であることを確認します。

fetch() リクエストに対するレスポンスは Stream オブジェクトです。つまり、json() メソッドを呼び出すと、ストリームの読み取りが非同期で行われるため、Promise が返されます。

レスポンス メタデータ

前の例では、Response オブジェクトのステータスと、レスポンスを JSON として解析する方法を確認しました。ヘッダーなど、Google がアクセスする可能性があるその他のメタデータを以下に示します。

fetch('users.json').then(function(response) {
    console.log(response.headers.get('Content-Type'));
    console.log(response.headers.get('Date'));

    console.log(response.status);
    console.log(response.statusText);
    console.log(response.type);
    console.log(response.url);
});

レスポンス タイプ

フェッチ リクエストを行うと、レスポンスには「basic」、「cors」、「opaque」の response.type が返されます。これらの types はリソースの取得元を示し、レスポンス オブジェクトの処理方法を通知するために使用できます。

同じオリジンのリソースに対してリクエストが行われた場合、レスポンスは basic タイプになり、レスポンスから表示できる内容に制限はありません。

別のオリジンのリソースに対してリクエストが行われ、CORs ヘッダーが返される場合、タイプは cors です。cors レスポンスと basic レスポンスはほぼ同じですが、cors レスポンスでは、表示できるヘッダーが Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma に制限されている点が異なります。

opaque レスポンスは、CORS ヘッダーを返さない別のオリジンのリソースに対するリクエストに対するリクエストです。不透明なレスポンスでは、返されたデータの読み取りやリクエストのステータスの表示ができません。つまり、リクエストが成功したかどうかを確認することができません。

特定のリクエストのみが解決されるように、取得リクエストのモードを定義できます。設定可能なモードは次のとおりです。

  • same-origin は、同じオリジンのアセットに対するリクエストに対してのみ成功し、他のすべてのリクエストは拒否されます。
  • cors は、同じオリジンと適切な CORs ヘッダーを返す他のオリジンのアセットに対するリクエストを許可します。
  • cors-with-forced-preflight は、実際のリクエストを行う前に、常にプリフライト チェックを実行します。
  • no-cors は、CORS ヘッダーがなく opaque レスポンスを返す他のオリジンにリクエストを行うためのものですが、前述のように、現時点ではウィンドウのグローバル スコープではこれを行えません。

モードを定義するには、fetch リクエストの 2 番目のパラメータとしてオプション オブジェクトを追加し、そのオブジェクトでモードを定義します。

fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'})
    .then(function(response) {
    return response.text();
    })
    .then(function(text) {
    console.log('Request successful', text);
    })
    .catch(function(error) {
    log('Request failed', error)
    });

Promise のチェーン

Promise の優れた機能の一つは、それらを連鎖させることです。フェッチの場合、フェッチ リクエスト間でロジックを共有できます。

JSON API を使用している場合は、ステータスを確認し、各レスポンスの JSON を解析する必要があります。Promise を返す個別の関数でステータスと JSON 解析を定義することで、コードを簡素化できます。これにより、最終データとエラーケースの処理だけを気にする必要がなくなります。

function status(response) {
    if (response.status >= 200 && response.status < 300) {
    return Promise.resolve(response)
    } else {
    return Promise.reject(new Error(response.statusText))
    }
}

function json(response) {
    return response.json()
}

fetch('users.json')
    .then(status)
    .then(json)
    .then(function(data) {
    console.log('Request succeeded with JSON response', data);
    }).catch(function(error) {
    console.log('Request failed', error);
    });

response.status を確認し、解決済みまたは拒否された Promise を返す Promise.resolve() または Promise.reject() の結果を返す status 関数を定義します。これは、fetch() チェーンで最初に呼び出されるメソッドです。解決されると、json() メソッドを呼び出し、response.json() 呼び出しから Promise を再度返します。この後、解析された JSON のオブジェクトが作成されます。解析が失敗した場合は、Promise が拒否され、 catch ステートメントが実行されます。

これにより、すべてのフェッチ リクエストでロジックを共有できるため、コードの保守、読み取り、テストが容易になります。

POST リクエスト

ウェブアプリで POST メソッドを使用して API を呼び出し、リクエストの本文で一部のパラメータを指定することは珍しくありません。

そのためには、fetch() オプションで method パラメータと body パラメータを設定します。

fetch(url, {
    method: 'post',
    headers: {
        "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
    },
    body: 'foo=bar&lorem=ipsum'
    })
    .then(json)
    .then(function (data) {
    console.log('Request succeeded with JSON response', data);
    })
    .catch(function (error) {
    console.log('Request failed', error);
    });

取得リクエストで認証情報を送信する

Cookie などの認証情報を使用して取得リクエストを行う場合は、リクエストの credentials"include" に設定する必要があります。

fetch(url, {
    credentials: 'include'
})

よくある質問

fetch() リクエストをキャンセルするにはどうすればよいですか?

現時点では取得をキャンセルする方法はありませんが、GitHub で議論されています。このリンクは @jaffathecake です。

ポリフィルはありますか?

GitHub にはフェッチ用のポリフィルがある@Nexii よろしくお願いします。

Service Worker では「no-cors」がサポートされているのに、時間枠ではサポートされていないのはなぜですか?

これはセキュリティ上の問題によるものです。詳しくは、こちらをご覧ください。