1073
999

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

お疲れさまXMLHttpRequest、こんにちはfetch

Last updated at Posted at 2015-11-27

Service Workersでプッシュ通知を受信できるようになったわけですが([1]: GCM)([2]: Web Push)、Chromeではバージョン48まではGCMで通知だけができるようになっただけで、メッセージ本体は通知を受けてからService Workerでサーバから改めて受け取るような実装をする必要があったりします。

ここで、Service Workersでは、XMLHttpRequestが使えません。その代わり、XMLHttpRequest (以下、XHR)に代わるWHATWGの仕様としてFetch APIがあり、Service WorkersではこのFetch APIを使うことになっていますので、その使い方を簡単に紹介します。

Fetch API自体は、Service Workers専用のものではなく、メインスレッドでもXHRの代わりに使うことが可能です。現時点で実装しているブラウザは、Service Workersが使えるChrome, Opera, Firefox等(Chrome, Opera等はごく一部の古いバージョンでは非対応)と、バージョン14以降のMicrosoft Edge、Safari 10.1以降となります。

なお、過去のバージョンのブラウザへの対応が必要となる場合は、Polyfillを使うと良いかもしれません。

基本的な使い方

まず、同じオリジン内のリソースをHTTP(S)のGETで単純に取得する場合は、次のようにします。

fetch('URLあるいは相対パスなど').then(...);

fetch()の結果はPromiseで返され、resolve関数には引数としてResponseオブジェクトが渡されます。ここで、取得した内容はBlob, ArrayBuffer, JSON, プレーンテキストのいずれかの形で受け取ることが出来ます。

Blobで受け取る場合
fetch(url).then(function(response) {
  return response.blob();
}).then(function(blob) {
  // blobにBlob型で結果が渡される
  ...
});
ArrayBufferで受け取る場合
fetch(url).then(function(response) {
  return response.arrayBuffer();
}).then(function(arrayBuffer) {
  // arrayBufferにArrayBuffer型で結果が渡される
  ...
});
JSONで受け取る場合
fetch(url).then(function(response) {
  return response.json();
}).then(function(json) {
  // jsonにJSONオブジェクトで結果が渡される
  ...
});
プレーンテキストで受け取る場合
fetch(url).then(function(response) {
  return response.text();
}).then(function(text) {
  // textに文字列で結果が渡される
  ...
});

様々なオプションを使う

fetch()メソッドでは、JSONで様々なオプションを渡すことで、HTTPリクエストを柔軟にカスタマイズできるのが大きな特徴です。JSONで一度に指定できるのでXHRよりも扱い方が楽になっています。

fetch('URLあるいは相対パスなど', {/* JSONでオプションを指定 */}).then(...);

POSTメソッド

オプションのmethodメンバにHTTPメソッド名を指定することが出来ます。また、メソッドが'POST'の場合は、bodyメンバにアップロードしたいデータを指定することができます。

POSTメソッドの例(フォームデータのアップロード)
fetch(url, {
  method: 'POST',
  body: new FormData(document.getElementById('<form>タグのid'))
}).then(function(response) {
  return response.json();
}).then(function(json) {
  ...
});
POSTメソッドの例(ファイル(Blob)のアップロード)
fetch(url, {
  method: 'POST',
  body: document.getElementById('<input type="file">タグのid')).files[0]
}).then(function(response) {
  return response.json();
}).then(function(json) {
  ...
});

クロスオリジンとクレデンシャル

CORSによるクロスオリジン接続を行いたい時は、オプションのmodeメンバに'cors'を指定します。なお、'same-origin'を指定すると同一オリジン以外の接続がエラーとなり、'no-cors'を指定するとクロスオリジン接続ができない場合にエラーとならずに空のレスポンスが返されます。

クロスオリジン接続の例
fetch(url, {
  mode: 'cors'
}).then(function(response) {
  return response.json();
}).then(function(json) {
  ...
});

また、デフォルトではクッキー等のクレデンシャルをHTTPリクエストに含めないようになっています。クッキー等を付けたい場合は、次のようにします。

クロスオリジン接続にクッキーを付けたい場合の例
fetch(url, {
  mode: 'cors',
  credentials: 'include'
}).then(function(response) {
  return response.json();
}).then(function(json) {
  ...
});

任意のHTTPリクエストヘッダを追加

オプションのheadersフィールドにHeadersオブジェクトもしくはJSONでHTTPリクエストヘッダの内容を指定することができます。

HTTPリクエストヘッダに任意のヘッダを追加する例(1)
fetch('https://www.googleapis.com/userinfo/v2/me', {
  headers: { 'Authorization': 'Bearer: (アクセストークン)' }
}).then(function(response) {
  return response.json();
}).then(function(json) {
  ...
});
HTTPリクエストヘッダに任意のヘッダを追加する例(2)
fetch('https://www.googleapis.com/userinfo/v2/me', {
  headers: new Headers({ 'Authorization': 'Bearer: (アクセストークン)' })
}).then(function(response) {
  return response.json();
}).then(function(json) {
  ...
});

Responseオブジェクトのその他の機能

ResponseオブジェクトのheadersプロパティにはHeadersオブジェクトとしてHTTPレスポンスヘッダの内容が格納されます。また、statusプロパティにはHTTPレスポンスのステータスコード(200など)が格納されます。

HTTPレスポンスヘッダを取得する例
fetch(url).then(function(response) {
  console.log(response.headers.get('content-type')); // 例えば、"text/html; charset=utf-8"
  console.log(response.status); // 例えば、200
});

Service Workersでfetch()を使う場合の注意事項

プッシュ通知の受信時の処理などでfetch()を使う場合、結果を受け取る処理のPromiseをevent.waitUntil()メソッドに渡す必要があります。そうしなければ、fetch()の受信処理が完了しないうちにService Workerが停止してしまいますので、ご注意下さい。

ServiceWorkersでfetch()を利用する例
self.addEventListener('push', function(evt) {
  var getEndpoint = self.registration.pushManager.getSubscription();
  var confirmPush = getEndpoint.then(function(subscription) {
    var form = new FormData();
    form.append('endpoint', subscription.endpoint);
    return fetch(pushServerUrl, {
      method: 'POST',
      body: form
    });
  });
  var getPushData = confirmPush.then(function(response) {
    return response.json();
  });
  var parseJSON = getPushData.then(function(json) {
    var data = json.data;
    ...
  });
  evt.waitUntil(parseJSON);
});
1073
999
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1073
999

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?