Fetch API を利用すると、リクエストやレスポンスといった HTTP のパイプラインを構成する要素を操作できるようになります。また fetch() メソッドを利用することで、非同期のネットワーク通信を簡単にわかりやすく記述できるようになります。

従来、このような機能は XMLHttpRequest を使用して実現されてきました。 Fetch はそれのより良い代替となるもので、サービスワーカーのような他の技術から簡単に利用することができます。 Fetch は CORS や HTTP 拡張のような HTTP に関連する概念をまとめて定義する場所でもあります。

fetch の仕様は jQuery.ajax() とは主に二つの点で異なっています。

  • fetch() から返される Promise は レスポンスが HTTP 404 や 500 を返して HTTP エラーステータスの場合でも拒否されません。代わりに (ok ステータスが false にセットて) 正常に解決し、拒否されるのはネットワークのエラーや、何かがリクエストの完了を妨げた場合のみです。
  • 既定では、 fetch はサーバーとの間で cookies を送受信しないため、サイトがユーザーセッションの維持に頼っている場合は未認証のリクエストになります (cookie を送るには、認証情報の init オプションを設定しておく必要があります)。
    2017年8月25日に、既定の認証情報のポリシーが same-origin に変更になり、 Firefox は 61.0b13 から変更しました。

基本的な fetch リクエストは、本当に簡単に設定できます。以下のコードを見てください。

fetch('http://example.com/movies.json')
  .then(function(response) {
    return response.json();
  })
  .then(function(myJson) {
    console.log(JSON.stringify(myJson));
  });

これはネットワーク越しに JSON ファイルを取得してコンソールに出力するスクリプトです。 fetch() の最も簡単な使い方は 1 つの引数 — fetch で取得したいリソースへのパス — のみをとり、レスポンス (Response オブジェクト) を含む promise を返します。

これはもちろんただの HTTP レスポンスであり、実際の JSON ではありません。 response オブジェクトから JSON を抽出するには、 json() メソッドを使用する必要があります。(Body のミックスインとして定義されていて、これは RequestResponse の両オブジェクトに実装されています。)

メモ: Body ミックスインは本文の内容を他の mime タイプとして展開する似たようなメソッドを提供しています。詳細は Body の節をご覧ください。

Fetch リクエストは、検索したリソースからの指示よりも Content Security Policyconnect-src ディレクティブによって制御されます。

リクエストにオプションを適用する

fetch() メソッドには 2 つ目の引数を適用することもできます。多数の設定をコントロールすることのできる init オブジェクトです。

すべての設定可能なオプションや詳細な説明を見るには fetch() を参照してください。

// POST メソッドの実装の例

postData(`http://example.com/answer`, {answer: 42})
  .then(data => console.log(JSON.stringify(data))) // JSON-string from `response.json()` call
  .catch(error => console.error(error));

function postData(url = ``, data = {}) {
  // 既定のオプションには * が付いています
    return fetch(url, {
        method: "POST", // *GET, POST, PUT, DELETE, etc.
        mode: "cors", // no-cors, cors, *same-origin
        cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
        credentials: "same-origin", // include, same-origin, *omit
        headers: {
            "Content-Type": "application/json; charset=utf-8",
            // "Content-Type": "application/x-www-form-urlencoded",
        },
        redirect: "follow", // manual, *follow, error
        referrer: "no-referrer", // no-referrer, *client
        body: JSON.stringify(data), // 本文のデータ型は "Content-Type" ヘッダーと一致する必要があります
    })
    .then(response => response.json()); // レスポンスの JSON を解析
}

認証情報つきのリクエストを送る

ブラウザーに認証情報の入ったリクエストを送るようにするには、オリジン間の呼び出しであっても、 credentials: 'include'init オブジェクトに追加して fetch() メソッドに渡します。

fetch('https://example.com', {
  credentials: 'include'  
})

リクエスト URL が呼び出しスクリプトと同一オリジンの場合だけクレデンシャルを送りたい場合、credentials: 'same-origin'を追加します。

// The calling script is on the origin 'https://example.com'

fetch('https://example.com', {
  credentials: 'same-origin'  
})

この代わりにブラウザーがリクエストにクレデンシャルを含んでないことを保証するには、credentials: 'omit'を使います。

fetch('https://example.com', {
  credentials: 'omit'  
})

JSON データをアップロードする

fetch() を使って JSON-エンコードしたデータを POST します。

var url = 'https://example.com/profile';
var data = {username: 'example'};

fetch(url, {
  method: 'POST', // or 'PUT'
  body: JSON.stringify(data), // data can be `string` or {object}!
  headers:{
    'Content-Type': 'application/json'
  }
}).then(res => res.json())
.then(response => console.log('Success:', JSON.stringify(response)))
.catch(error => console.error('Error:', error));

ファイルのアップロード

ファイルは HTML <input type="file" /> input 要素や、 FormData()fetch() を使ってアップロードできます。

var formData = new FormData();
var fileField = document.querySelector("input[type='file']");

formData.append('username', 'abc123');
formData.append('avatar', fileField.files[0]);

fetch('https://example.com/profile/avatar', {
  method: 'PUT',
  body: formData
})
.then(response => response.json())
.catch(error => console.error('Error:', error))
.then(response => console.log('Success:', JSON.stringify(response)));

複数のファイルのアップロード

HTML の <input type="file" /> 入力欄と FormData()fetch() を使用してファイルをアップロードすることができます。

var formData = new FormData();
var photos = document.querySelector("input[type='file'][multiple]");

formData.append('title', 'My Vegas Vacation');
formData.append('photos', photos.files);

fetch('https://example.com/posts', {
  method: 'POST',
  body: formData
})
.then(response => response.json())
.then(response => console.log('Success:', JSON.stringify(response)))
.catch(error => console.error('Error:', error));

fetch が成功したかチェックする

ネットワークエラーに遭遇すると fetch() promise は TypeError を返して reject 状態になります。サーバー側の CORS が適切に設定されていない場合も同様です(アクセス権の問題ですけどね) — 一方で例えば 404 はネットワークエラーを構成しません。fetch() が成功したかどうかの明確な判定をするには、プロミスが解決されて、Response.ok プロパティが true になっているかなどを確認します。次のようなコードになるでしょう。

fetch('flowers.jpg').then(function(response) {
  if(response.ok) {
    return response.blob();
  }
  throw new Error('Network response was not ok.');
}).then(function(myBlob) { 
  var objectURL = URL.createObjectURL(myBlob); 
  myImage.src = objectURL; 
}).catch(function(error) {
  console.log('There has been a problem with your fetch operation: ', error.message);
});

独自の request オブジェクトを fetch に渡す

fetch() を呼ぶときにリクエストしたいリソースへのパスを渡す代わりに、Request() コンストラクターを使用して Request オブジェクトを作成して fetch() メソッドの引数として渡すこともできます。

var myHeaders = new Headers();

var myInit = { method: 'GET',
               headers: myHeaders,
               mode: 'cors',
               cache: 'default' };

var myRequest = new Request('flowers.jpg', myInit);

fetch(myRequest).then(function(response) {
  return response.blob();
}).then(function(myBlob) {
  var objectURL = URL.createObjectURL(myBlob);
  myImage.src = objectURL;
});

fetch() メソッドの引数と全く同じ引数を Request() に適用させることができます。また、 request オブジェクトのコピーを作成するためにすでに存在する request オブジェクトを渡すこともできます。

var anotherRequest = new Request(myRequest, myInit);

これは、リクエストとレスポンスの本文を一つだけ使用するのでとても有用です。必要であれば、init オプションを変化させながらリクエスト / レスポンスを再利用できるようにコピーします。コピーをは body が読まれる前でなければならず、コピーの中の body を読むとオリジナルのリクエストも既読にマークされます。

メモ: clone() メソッドを利用してコピーを生成することもできます。これには、ほかのコピーメソッドと若干異なる意味があります — 古いリクエストの body がすでに読み込まれていた場合、前者は失敗しますが、clone() は失敗しません (レスポンスでも同じです)。

Headers

Headers インターフェースでは、 Headers() コンストラクターを使用して、ヘッダーオブジェクトを作成することができます。ヘッダーオブジェクトはシンプルな複数の名前と値の Map です。

var content = "Hello World";
var myHeaders = new Headers();
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Content-Length", content.length.toString());
myHeaders.append("X-Custom-Header", "ProcessThisImmediately");

同じことはコンストラクターに配列の配列かオブジェクトリテラルを渡すことで達成できます。

myHeaders = new Headers({
  "Content-Type": "text/plain",
  "Content-Length": content.length.toString(),
  "X-Custom-Header": "ProcessThisImmediately",
});

ヘッダーの中身を見たり、検索することができます。

console.log(myHeaders.has("Content-Type")); // true
console.log(myHeaders.has("Set-Cookie")); // false
myHeaders.set("Content-Type", "text/html");
myHeaders.append("X-Custom-Header", "AnotherValue");
 
console.log(myHeaders.get("Content-Length")); // 11
console.log(myHeaders.get("X-Custom-Header")); // ["ProcessThisImmediately", "AnotherValue"]
 
myHeaders.delete("X-Custom-Header");
console.log(myHeaders.get("X-Custom-Header")); // [ ]

いくつかの操作は ServiceWorkers でしか役立ちませんが、ヘッダーを操作するためのより良い API を提供しています。

Headers のメソッドはすべて、有効な HTTP ヘッダーではない名前が渡されたとき TypeError を投げます。 immutable ガード (下記参照) がかかっている場合も、 TypeError を投げます。もしくはエラーを投げずに失敗します。例を見てください。

var myResponse = Response.error();
try {
  myResponse.headers.set("Origin", "http://mybank.com");
} catch(e) {
  console.log("銀行のふりをしないで下さい!");
}

ヘッダーの良い使用方法としては、以下のように、処理を行う前に、コンテンツタイプが正しいかどうか判定する等の使い方があります。

fetch(myRequest).then(function(response) {
    var contentType = response.headers.get("content-type");
    if(contentType && contentType.includes("application/json")) {
      return response.json();
    }
    throw new TypeError("Oops, we haven't got JSON!");
  })
  .then(function(json) { /* process your JSON further */ })
  .catch(function(error) { console.log(error); });

Guard

ヘッダーは、リクエストで送信でき、レスポンスで受信できます。また、どの情報が変更できる(または、すべき)かといったさまざまな制限があります。そのため、ヘッダーは guard プロパティを持っています。これはリクエストやレスポンスに含まれませんが、ヘッダーオブジェクトでできる変更操作に影響を与えます。

設定できるガード値には以下のものがあります。

  • none: 既定値です。
  • request: リクエスト (Request.headers) で使用できる値のみにヘッダーを保護する。
  • request-no-cors: Request.mode no-cors で生成されたリクエスト (Request.headers) で使用できる値のみにヘッダーを保護する。
  • response: レスポンス (Response.headers) で使用できる値のみにヘッダーを保護する。
  • immutable: 主に ServiceWorker で使用されます。ヘッダーを読み取り専用にします。

メモ: request のカードされたヘッダーの Content-Length ヘッダーは追加や変更できない可能性があります。同様に、レスポンスヘッダに Set-Cookie を挿入することはできません。ServiceWorker は、同期レスポンスを経由してクッキーを設定できません。

Response オブジェクト

すでに見てきたように, Response インスタンスは、 fetch() プロミスが解決(resolve)されたときに返り値として渡されます。

下記はどんな response オブジェクトでも共通で使用できる response プロパティです。

  • Response.status — HTTP ステータスコードの整数値 (デフォルト値は 200)
  • Response.statusText — HTTP ステータスコードのメッセージと一致する文字列 (デフォルト値は "OK")
  • Response.ok — 上述の例で使用したように、これは HTTP ステータスコードが 200 から 299 のうちに収まってるかどうかのショートハンドです。これは Boolean を返します。

Response オブジェクトは JavaScript で動的に作ることもできます。これは ServiceWorkers 内において非常に役立ちます。例えばリクエストを受け取ったときに respondWith() メソッドによってカスタマイズされたレスポンスを返すようなときに役立ちます。

var myBody = new Blob();

addEventListener('fetch', function(event) { // ServiceWorker intercepting a fetch
  event.respondWith(
    new Response(myBody, {
      headers: { "Content-Type" : "text/plain" }
    })
  );
});

Response() コンストラクターはオプションとして 2 つの引数をとることができます — レスポンス本文と初期化オブジェクトです。 (Request() が受け取れるものと似ています。)

メモ: 静的メソッド error() は単純にエラーレスポンスを返します。同様に redirect() メソッドも 指定した URL にリダイレクトするレスポンスを返します。これらはサービスワーカーにのみ関連しています。

Body

リクエストもレスポンスもボディを持っています。body は以下のタイプのいずれかのインスタンスです。

Body ミックスインは RequestResponse に実装されていて、コンテンツを抜き出すために以下のメソッドが定義されています。これらはすべて最終的に実際の中身で解決されるプロミスを返します。

これらは非テキストデータを XHR よりはるかに楽に扱うことができます。

Request 本文は、body パラメータを渡すことによって設定することができます。

var form = new FormData(document.getElementById('login-form'));
fetch("/login", {
  method: "POST",
  body: form
});

Request や Response (と fetch() 関数の拡張) は自動的にコンテンツタイプを決定しようとします。Request もまた、指定されていなければ自動で Content-Type ヘッダーを設定しようとします。

使用可能かどうかの判別

Fetch API が利用できるかどうかは、HeadersRequestResponsefetch() のいずれかが Window もしくは Worker のスコープで参照できるかどうかによって判断できます。判断を行っている例は次のようになります。

if (self.fetch) {
    // ここで fetch リクエストを実行
} else {
    // XMLHttpRequest で何か実行する?
}

Polyfill

Fetch がサポートされていないブラウザーを使うため、非サポートブラウザー用の機能を再生成する Fetch Polyfill が利用できます。

仕様書

仕様書 状態 備考
Fetch 現行の標準 初回定義

ブラウザーの対応

Update compatibility data on GitHub
デスクトップモバイル
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewAndroid 版 ChromeEdge MobileAndroid 版 FirefoxAndroid 版 OperaiOS 版 SafariSamsung Internet
基本対応
実験的
Chrome 完全対応 42Edge 完全対応 14Firefox 完全対応 39
完全対応 39
完全対応 34
無効
無効 From version 34: this feature is behind the dom.fetch.enable preference. To change preferences in Firefox, visit about:config.
完全対応 52
補足
補足 fetch() now defined on WindowOrWorkerGlobalScope mixin.
IE 未対応 なしOpera 完全対応 29
完全対応 29
完全対応 28
無効
無効 From version 28: this feature is behind the Experimental Web Platform Features preference.
Safari 完全対応 10WebView Android 完全対応 42Chrome Android 完全対応 42Edge Mobile 完全対応 14Firefox Android 完全対応 39
完全対応 39
完全対応 34
無効
無効 From version 34: this feature is behind the dom.fetch.enable preference. To change preferences in Firefox, visit about:config.
完全対応 52
補足
補足 fetch() now defined on WindowOrWorkerGlobalScope mixin.
Opera Android ? Safari iOS 完全対応 10Samsung Internet Android ?
Streaming response body
実験的
Chrome 完全対応 43Edge 完全対応 14Firefox 完全対応 あり
無効
完全対応 あり
無効
無効 This feature is behind the dom.streams.enabled preference and the javascript.options.streams preference. To change preferences in Firefox, visit about:config.
IE 未対応 なしOpera 完全対応 29Safari 完全対応 10WebView Android 完全対応 43Chrome Android 完全対応 43Edge Mobile 完全対応 14Firefox Android 未対応 なしOpera Android 未対応 なしSafari iOS 完全対応 10Samsung Internet Android ?
Support for blob: and data:
実験的
Chrome 完全対応 48Edge 未対応 なしFirefox ? IE 未対応 なしOpera ? Safari ? WebView Android 完全対応 43Chrome Android 完全対応 43Edge Mobile 未対応 なしFirefox Android ? Opera Android ? Safari iOS ? Samsung Internet Android ?
referrerPolicyChrome 完全対応 52Edge 未対応 なしFirefox 完全対応 52IE 未対応 なしOpera 完全対応 39Safari 完全対応 11.1WebView Android 完全対応 52Chrome Android 完全対応 52Edge Mobile 未対応 なしFirefox Android 完全対応 52Opera Android 完全対応 39Safari iOS 未対応 なしSamsung Internet Android ?
signal
実験的
Chrome ? Edge ? Firefox 完全対応 57IE 未対応 なしOpera ? Safari 未対応 なしWebView Android ? Chrome Android ? Edge Mobile ? Firefox Android 完全対応 57Opera Android ? Safari iOS 未対応 なしSamsung Internet Android ?

凡例

完全対応  
完全対応
未対応  
未対応
実装状況不明  
実装状況不明
実験的。動作が変更される可能性があります。
実験的。動作が変更される可能性があります。
実装ノートを参照してください。
実装ノートを参照してください。
ユーザーが明示的にこの機能を有効にしなければなりません。
ユーザーが明示的にこの機能を有効にしなければなりません。

関連情報

ドキュメントのタグと貢献者

最終更新者: mfuji09,