#071
posted on 2022.05.27

Fetchの基礎知識。

JavaScriptでクライアントサイドからサーバーサイドへの非同期通信を実行して別ベージのコンテンツやリソースの取得ができるFetchについての基礎知識のメモ。

 

 

FetchとXMLHttpRequestの違い

「Fetch」と同じ非同期通信が可能な「XMLHttpRequest」との違い。

  • 「Fetch」の方が「XMLHttpRequest」よりも新しく、機能が優れるので、現在は「Fetch」の方が推奨されている。
  • ほとんどの「XMLHttpRequest」の機能がIE対応だが、「Fetch」は完全IE非対応。
  • 「XMLHttpRequest」はアップロードとダウンロードの両方の進行状況を追跡できるが、「Fetch」はダウンロードのみでアップロードの進行状況の追跡はできない。
  • 別ページの「HTML」を取得したい場合、「XMLHttpRequest」はリソースを直接「XML」や「HTML」としてparse(解釈)して取得できるが、「Fetch」では一旦「文字列」としてデータを取得して「DOMParser」インターフェイスでparse(解釈)し直す必要がある。

 

 

Fetch

(1) Fetch

「Fetch API」は、指定したパスにリクエストを送り、そのレスポンスとしてリソースを取得するための機能を提供する。(HTTP通信のリクエスト送信とレスポンス受信をJavaScritpで処理するために利用される。)

「fetch()」メソッドを使用して非同期通信(または同期通信)を実行し、主に、別ページのコンテンツやサーバー上のリソースの取得などに利用される。

※ 同期通信は、JavaScriptの他の処理を一時的に止めてしまうので基本的に使われない。

※ Fetch APIについてのMozillaの公式ドキュメント

 

(2) Fetchの要約

  • 「Fetch」はIE非対応。
  • 「Fetch API」では、HTTP通信の「ヘッダー」、「リクエスト」、「レスポンス」を扱うためのインターフェイスが定義されている。
  • Headersオブジェクト、Requestオブジェクト、Responseオブジェクトを内部的に処理してHTTP通信を実行する。
  • Headersオブジェクトは、HTTP通信のリクエストとレスポンスの「ヘッダー」を表す。
  • Requestオブジェクトは、取得したいリソースへの「リクエスト」の内容を表す。
  • Responseオブジェクトは、リクエストに対する「レスポンス」の内容を表す。
  • 「fetch()」メソッドを使用して、「取得したいリソースのパス」と「処理に関するオプション」を引数に指定してリクエストを作成・送信し、そのレスポンスを受信する。(「fetch()」メソッドでのリクエストに対するレスポンスに解決するPromiseを返す。)
  • 「fetch()」メソッドはPromiseベースなのでPromiseのメソッドが使用できる。(Promiseのすべてのメソッドが使えるのかは不明。)
  • 「fetch()」メソッドのPromiseは、リクエスト先が応答した時(完全なレスポンスがダウンロードされる前)にresolve(解決)され、「then()」メソッドでレスポンス(Responseオブジェクト)を受け取る。
  • Responseオブジェクトを受け取った段階で、完全なレンスポンスを取得するためのResponseオブジェクトのメソッドが利用できる。
  • Responseオブジェクトのメソッドで完全なレスポンスを取得することで、レスポンス内のコンテンツ本体が利用できる。(このメソッドは、完全なレスポンスの取得で解決されるPromiseオブジェクトを返す。)
  • Cookieやユーザーの資格情報 (HTTPのBasic認証など)は、「リクエスト先のURL」が「呼び出し元のスクリプト」と同一オリジンだった場合にだけリクエストに含まれて送信される。(メソッドのオプション指定で、クロスオリジン対応や非送信にも変更できる。)

 

オリジン

オリジンは、ウェブコンテンツへのアクセスに使われる「URLのスキーム」(プロトコル)、「ホスト」(ドメイン)、「ポート番号」の3つによって定義される。

この3つがリクエスト元とリクエスト先で同じ場合は「同一オリジン」、ひとつでも異なる場合は「クロスオリジン」となる。

操作内容によっては同一オリジンでのみ許可されているが、リモート側が特別なヘッダー情報を送信することでクロスオリジンを許可することができる。このヘッダー情報によって、クロスオリジンリクエストのレスポンスに、フロントエンドのJavaScriptコードがアクセスすることを許可するシステムを「CORS」(Cross-Origin Resource Sharing)と呼ぶ。

 

(3) Headersオブジェクト

Headersオブジェクトは、「Fetch」でのHTTP通信のリクエストとレスポンスのヘッダー情報を表す。

※ HeadersについてのMozillaの公式ドキュメント

  • Headersオブジェクトのメソッドを利用して、ヘッダー情報の取得、設定、追加、削除ができる。
  • 新しいHeadersオブジェクトを生成するにはHeaders()コンストラクターを使用する。
  • Headersオブジェクトは、0個以上の「名前」と「値」のペアで構成されるヘッダーのリストを保持している。
  • 一部のヘッダー情報は設定が禁止されている。(「forbidden header name」の公式ドキュメント。)
  • Requestオブジェクト、Responseオブジェクトの「headers」プロパティーで、それぞれのHeadersオブジェクトを参照できる。

 

[ Headersオブジェクトを生成する例 ]

Headers()コンストラクターを使用してHeadersオブジェクトを新しく生成する例。

※ Headers()コンストラクターについてのMozillaの公式ドキュメント

  1. new演算子を付加してHeaders()コンストラクターを呼び出し、Headersオブジェクトを生成。
  2. append()メソッドでヘッダー情報を追加。
  3. get()メソッドでヘッダー情報を取得。

※ Headers()コンストラクターの引数に、「オブジェクトリテラル」か「配列リテラル」でヘッダー情報を指定して、生成と同時に設定することもできる。

//Headersオブジェクトを生成
const ag2headers = new Headers();
//ヘッダー情報を追加
ag2headers.append('Content-Type', 'text/xml');
//名前を指定してヘッダー情報を取得
ag2headers.get('Content-Type');

//Headersオブジェクトの生成時にヘッダー情報を設定する場合
const ag2headers = new Headers({
  'Content-Type': 'text/xml'
});

 

(4) Requestオブジェクト

Requestオブジェクトは、「Fetch」でのリクエスト送信の内容を表す。

※ RequestについてのMozillaの公式ドキュメント

  • Requestオブジェクトは、「fetch()」メソッドの処理の中でリソースへのリクエストとして送信される。
  • Requestオブジェクトのプロパティー(「method」や「body」など)を参照して、設定されているリクエストの内容を取得できる。
  • 新しいRequestオブジェクトを生成するにはRequest()コンストラクターを使用する。
  • Request()コンストラクターの引数にオプションを指定することで、リクエストの内容を設定できる。

 

「Fetch」でリクエストに本文(body)を追加する場合に使用できるデータの形式は以下のいずれか。

  • 文字列。
  • JSONデータ。(任意のオブジェクトをJSONデータとして送信する場合は、「JSON.stringify()」メソッドでJSON化する。)
  • バイナリーデータ : ArrayBufferオブジェクト、ArrayBufferのViewオブジェクト(Uint8Arrayなど)、Blobオブジェクト(またはFileオブジェクト)など。
  • フォーム : FormDataオブジェクト。(HTMLのform要素に該当。)
  • 検索パラメータ : URLSearchParamsオブジェクト。

※ リクエスト通信がGETメソッドまたはHEADメソッドの場合は本文を持てない。

※ JSONなら「application/json」など、送信するデータのタイプに合わせてリクエストヘッダーの「Content-Type」を設定する必要がある。(データとなるオブジェクトが既にタイプ情報を保持していれば設定不要。)

※ 「FormData」オブジェクトをJSON化するには、一度「Object.fromEntries()」メソッドで型を変換してから「JSON.stringify()」メソッドで変換する。

 

[ Requestオブジェクトを生成する例 ]

Request()コンストラクターを使用してRequestオブジェクトを新しく生成する例。

※ Request()コンストラクターについてのMozillaの公式ドキュメント

  1. new演算子を付加してRequest()コンストラクターを呼び出し、Requestオブジェクトを生成。
  2. 第1引数に「取得したいリソースのパス」(リクエスト送信先)を指定。
  3. 第2引数に「リクエストに適用するカスタム設定を含むオプションオブジェクト」を指定。(省略可。)

※ オプションの「headers」の値には、Headersオブジェクトを指定することもできる。

const ag2request = new Request('取得するリソースのパス', {
  //オプション指定
  method: 'POST',
  headers: {
    'Content-Type': 'text/xml'
  },
  body: '送信するデータ',
  mode: 'cros'
});

 

(5) Responseオブジェクト

Responseオブジェクトは、「Fetch」でのリクエストに対するレスポンスの内容を表す。

※ ResponseについてのMozillaの公式ドキュメント

  • 「fetch()」メソッドの処理の中で、リソースへのリクエストに対するレスポンス(Responseオブジェクト)を受け取る。
  • 「fetch()」メソッドはPromiseベースなので、Promiseとしてレスポンスを処理する。
  • レスポンスは、「fetch()」メソッドでリクエストを送信してPromiseがresolve(解決)されたときに返値として渡される。
  • 渡されるレスポンスの本文(body)はHTTPレスポンスの全体なので、Responseオブジェクトのメソッドを使用して指定の形式に変換して取得する。
  • レスポンスデータは、指定の形式で解釈した結果でresolve(解決)する第2のPromiseとして返される。

 

[ Responseオブジェクトのメソッド ]

受け取ったレスポンスのデータ形式を変換するResponseオブジェクトのメソッド。

  • arrayBuffer() : ArrayBufferオブジェクト。
  • blob() : Blobオブジェクト。
  • formData() : FormDataオブジェクト。
  • json() : JSON。
  • text() : 文字列。

※ レスポンスの本文を、指定した形式でresolve(解決)するPromiseを返す。

※ 複数のメソッドを指定することはできない。(レスポンスの本文はすぐに解決して処理されるので、最初に指定したメソッドのみが有効。)

 

[ Responseオブジェクトのプロパティー ]

Responseオブジェクトが持つ主なプロパティー。

  • ok : HTTPステータスコードをチェックし、200番台なら「true」を返し、それ以外なら「false」を返す。
  • status : HTTPステータスコードを整数値で返す。(「200」など。)
  • statusText : HTTPステータスコードに対応したステータスメッセージを返す。 (「200」なら「OK」など。)

 

(6) fetch()メソッド

「fetch()」メソッドを使用して、指定した「取得したいリソースのパス」にリクエストを送信し、レスポンスとしてリソースを取得する。

※ fetch()メソッドについてのMozillaの公式ドキュメント

  • 第1引数に「取得したいリソースのパス」、第2引数に「リクエスト内容を設定するオプション」を指定する。(オプションは省略可。)
  • 「fetch()」メソッドはWindowOrWorkerGlobalScopeミックスインのメソッドで、ネットワークからリソースを取得するプロセスを開始し、レスポンスが利用できるようになったらPromiseを返す。
  • 送信したリクエストに対するレスポンスを表すResponseオブジェクトでresolve(解決)するPromiseを返す。
  • Promiseなので、「then()」メソッドの処理がresolve(解決)されたときにレスポンス(Responseオブジェクト)を受け取る。
  • 「fetch()」メソッドで返されるPromiseは、レスポンスが「404」や「500」などのHTTPエラーステータスの場合でもreject(拒否)されない。
  • 何かがリクエストの完了を妨げた場合はTypeErrorでPromiseがreject(拒否)される。(リクエスト先が存在しない場合やネットワーク障害があった場合など。)

 

[ 指定できるオプション ]

「fetch()」メソッドの第2引数のオプション指定で、送信するリクエストの内容を設定できる。(省略可。)

  • method : HTTPメソッド。POST、PUT、DELETEなど。(既定値は「GET」。)
  • headers : リクエストに追加するヘッダー。Headersオブジェクトかオブジェクトリテラルで指定する。
    body : リクエストに追加する本文。HTTPメソッドが「GET」や「HEAD」の場合は使用できない。(既定値は「undefined」。)
  • mode : 使用するモード。クロスオリジンリクエストにどう対応するかの設定。
  • credentials : 認証情報の送信設定。クロスオリジンでCookieと認証情報を送信する場合は設定が必要。
  • cache : 使用するキャッシュモード。(既定値は「default」。)
  • redirect : リクエスト先でリダイレクトが発生した場合の対応設定。(既定値は「follow」でリダイレクトに従う。)
  • referrer : 送信するリファラーの内容を設定。
  • referrerPolicy : リファラーを送信するかの設定。(既定値は「no-referrer-when-downgrade」で「SSLサイトから非SSLへのリクエスト」以外は常にリファラーを送信。)
  • integrity : 送信するハッシュ値の設定。設定した場合、リソースのハッシュ値と比較チェックして一致しない場合はエラーになる。(「sha256-abcdef1234567890」のようなハッシュを設定する。)
  • keepalive : リクエスト処理中にドキュメントがアンロードされた場合、バックグラウンドでリクエストを継続するかの設定。(既定値は「false」。)
  • signal : リクエスト処理中にキャンセルさせるための設定。キャンセル処理を実装したい場合は、事前に「AbortController」オブジェクトを生成して「signal」に設定しておく必要がある。(後述。)

 

[ fetch()メソッドの記述方法 ]

「fetch()」メソッドでリソースを取得する基本的な記述方法の例。

  1. 第1引数に「取得したいリソースのパス」、第2引数に「リクエストの内容を設定するオプション」を指定。
  2. Promiseの「then()」メソッドの処理でレスポンス(Responseオブジェクト)を受け取る。
  3. レスポンスの「ok」プロパティーをチェックして、「false」(HTTPステータスコードが200番台以外)の場合はエラーを表示。
  4. 受け取ったレスポンスを任意のデータ形式(下記ではテキスト形式)で取得してPromiseを解決。(取得して解決した段階で次のメソッドに移行するので、ここではデータを参照できない。)
  5. 変換したレスポンスのデータを第2のPromiseで受け取って表示。
fetch('取得したいリソースのパス', {
  //オプションを指定
  //POSTでデータを送信したい場合
  method : 'POST',
  body: '送信する本文データ'
}).then((response)=>{
  //ステータスコードがエラーの範囲の場合
  if(!response.ok) throw new Error('Network Response Error.');

  //処理...

  //指定の形式でレスポンスを取得してPromiseを解決して渡す
  return response.text();//テキスト形式でレスポンスを取得
}).then((result)=>{
  console.log(result);//取得したレスポンス
  //処理...
}).catch((error)=>{
  //エラーの場合
  console.error('Fetch Request Error :', error);
});

 

(7) リソースのダウンロード進行状況を取得

「fetch()」メソッドのレスポンスの受信処理で、リソースのダウンロードの進行状況を取得する方法。

「FileReader」オブジェクトを利用し、「progress」イベントが発生する度に現在読み込みが完了しているファイルサイズを取得する。

※ FileReaderオブジェクトの基礎知識は前の記事を参照。

fetch('取得したいリソースのパス', {
  method : 'POST',
  body: '送信する本文データ'
}).then((response)=>{
  let responseData = response.text();//テキスト形式でレスポンスを取得

  //FileReaderオブジェクトを生成
  const responseReader = new FileReader();
  //ダウンロードの進行状況の取得と表示
  responseReader.addEventListener('progress', (event) => {
    if(event.loaded && event.total){
      let ag2percent = Math.round((event.loaded / event.total) * 100);
      console.log('Download Progress :');
      console.log(event.loaded + ' bytes / '+event.total + ' bytes ('+ag2percent+' %)');
    }
  });
  //ダウンロードが完了した場合
  responseReader.addEventListener('load', (event) => {
    responseData = responseReader.result;
  });

  //リソースの読み込みを実行
  let ag2blob = new Blob([responseData]);
  responseReader.readAsText(ag2blob);//引数はBlobかFileオブジェクトである必要がある

  //取得したレスポンスを渡す
  return responseData;
}).then((result)=>{
  console.log(result);
}).catch((error)=>{
  console.error('Fetch Request Error :', error);
});

 

(8) Fetchのキャンセル

「fetch()」メソッドを実行したあと、そのリクエストの処理中にキャンセルさせる方法。

 

「AbortController」オブジェクトを利用してキャンセル処理を実装する。

  1. AbortController()コンストラクターで「AbortController」オブジェクトを生成。
  2. 「fetch()」メソッドのオプションの「signal」に、生成した「AbortController」オブジェクトの「signal」プロパティーを設定しておく。
  3. 「Fetch」を実行。
  4. 「Fetch」の処理中にキャンセルしたいタイミングで「AbortController」オブジェクトの「abort()」メソッドを実行。
  5. 「abort」イベントが発火して、「Fetch」の処理がキャンセルされる。

※ この方法で処理がキャンセルされたときのPromiseは「AbortError」というエラーでreject(拒否)される。

//AbortControllerオブジェクトを生成
const ag2controller = new AbortController();

//通常のfetchメソッドの記述
fetch('取得したいリソースのパス', {
  method : 'POST',
  body: '送信する本文データ',
  signal: ag2controller.signal
}).then((response)=>{
  return response.text();
}).then((result)=>{
  console.log(result);
}).catch((error)=>{
  console.error('Fetch Request Error :', error);
});

//Fetchの中止を実行
ag2controller.abort();

 

 

この記事をシェア
この記事のURL

https://memo.ag2works.tokyo/post-4424/

コピー
この記事のタイトル

Fetchの基礎知識。 | memo メモ [AG2WORKS]

コピー
この記事のリンクタグ

<a href="https://memo.ag2works.tokyo/post-4424/" target="_blank" rel="noopener">Fetchの基礎知識。 | memo メモ [AG2WORKS]</a>

コピー
※ フィールドをクリックでコピーするテキストの編集ができます。

この記事へのコメント

コメントの書き込みはまだありません。

  • コメント内のタグはエスケープ処理され、文字列として出力されます。
  • セキュリティーのため、投稿者のIPアドレスは取得されます。
  • 管理者が内容を不適切と判断したコメントは削除されます。
  • このフォームにはスパム対策として、Googleの提供するreCAPTCHAシステムが導入されています。
    (Google Privacy Policy and Terms of Service.)