fetch() の概要

fetch() を使用すると、XMLHttpRequest(XHR)と同様のネットワーク リクエストを行うことができます。主な違いは、Fetch API が Promise を使用していることです。Promise には、XMLHttpRequest API の複雑なコールバックを回避するのに役立つ、よりシンプルな API があります。

Browser Support

  • Chrome: 42.
  • Edge: 14.
  • Firefox: 39.
  • Safari: 10.1.

Source

Promise を使用したことがない場合は、JavaScript Promise の概要をご覧ください。

基本的な Fetch リクエスト

以下に、XMLHttpRequest を使用して実装した例と、fetch を使用して実装した例を示します。URL をリクエストし、レスポンスを取得して、JSON として解析します。

XMLHttpRequest

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

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

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

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

フェッチ

フェッチ リクエストは次のようになります。

fetch('./api/some.json')
  .then(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(err => {
    console.log('Fetch Error :-S', err);
  });

fetch() リクエストでは、XHR の例と同じ処理を行うために必要な呼び出しは 1 回だけです。レスポンスを処理するには、まずレスポンス ステータスが 200 であることを確認してから、レスポンスを JSON として解析します。fetch() リクエストに対するレスポンスは Stream オブジェクトです。つまり、json() メソッドを呼び出すと、Promise が返されます。ストリームは非同期で発生します。

レスポンスのメタデータ

前の例では、Response オブジェクトのステータスと、レスポンスを JSON として解析する方法を示しました。ヘッダーなど、アクセスする可能性のある他のメタデータを処理する方法は次のとおりです。

fetch('users.json').then(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 レスポンスに似ていますが、表示できるヘッダーが Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma に制限されます。

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(response => response.text())
  .then(text => {
    console.log('Request successful', text);
  })
  .catch(error => {
    log('Request failed', error)
  });

Promise チェーン

Promise の優れた機能の一つは、Promise を連結できることです。fetch() の場合、これによりフェッチ リクエスト間でロジックを共有できます。

JSON API を使用している場合は、各レスポンスのステータスを確認し、JSON を解析する必要があります。ステータスと JSON 解析を、Promise を返す別々の関数で定義し、fetch リクエストを使用して最終的なデータとエラーケースのみを処理することで、コードを簡素化できます。

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(data => {
    console.log('Request succeeded with JSON response', data);
  }).catch(error => {
    console.log('Request failed', error);
  });

この例では、response.status をチェックし、解決された Promise を Promise.resolve() として返すか、拒否された Promise を Promise.reject() として返す status 関数を定義しています。これは、fetch() チェーンで最初に呼び出されるメソッドです。

Promise が解決されると、スクリプトは json() メソッドを呼び出します。このメソッドは、response.json() 呼び出しから 2 番目の 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(data => {
    console.log('Request succeeded with JSON response', data);
  })
  .catch(error => {
    console.log('Request failed', error);
  });

フェッチ リクエストで認証情報を送信する

Cookie などの認証情報を使用してフェッチ リクエストを行うには、リクエストの credentials 値を "include" に設定します。

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