Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

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);
});
tomoyukilabs
Qiitaでは今のところ、主にWeb標準関連の記事を書いております。
https://github.com/tomoyukilabs
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした