これは実験段階の機能です。
この機能は複数のブラウザで開発中の状態にあります。互換性テーブルをチェックしてください。また、実験段階の機能の構文と挙動は、仕様変更に伴い各ブラウザの将来のバージョンで変更になる可能性があることに注意してください。
Fetch API を利用すると、リクエストやレスポンスといった HTTP のパイプラインを構成する要素を操作できるようになります。またfetch()
メソッドを利用することで、非同期のネットワーク通信を簡単にわかりやすく記述できるようになります。
従来、このような機能は XMLHttpRequest
によって提供されてきました。Fetch は、そのより良い代替で、Service Workers
のような技術から簡単に利用することが可能です。また CORS や HTTP 拡張のような HTTP に関連する概念をまとめて定義してもいます。
ブラウザの実装状況
Fetch の実装はかなりの初期段階にありますが、進んでもいます。Firefox 39 以降、もしくは Chrome 42 以降であれば、標準で利用できます。
すぐにでも Fetch を利用したいなら、Fetch Polyfill の利用すると良いでしょう。これは対応していないブラウザ向けに、Fetch で定義されている機能を提供します。これで Fetch を利用することは可能ですが、この機能自体が実験的なもので、不安定なものであることは受け入れなければなりません。
付記: Fetch の仕様 が Streams の仕様 と異なる可能性が出てきましたが、 将来的にはこの二つは統合される予定です。詳しくは Fetch API integrated with Streams を参照してください。
使用可能かどうかの判別
Fetch API が利用できるかどうかは、Headers
、Request
、Response
、fetch()
のいずれかが Window
もしくは Worker
のスコープで参照できるかどうかによって判断できます。判断を行っている例は次のようになります:
if(self.fetch) { // ここで fetch リクエストを実行 } else { // XMLHttpRequest で何か実行する? }
fetch リクエストを作成する
基本的な fetch はとても簡単に作成できます。 下のコードを見てください。
var myImage = document.querySelector('img'); fetch('flowers.jpg') .then(function(response) { return response.blob(); }) .then(function(myBlob) { var objectURL = URL.createObjectURL(myBlob); myImage.src = objectURL; });
これはネットワークごしに画像を取得して <img>
要素に挿入するスクリプトです。fetch() の最も簡単な使い方として、一つの引数のみ渡します。fetch() で取得したいリソースへのパスです。 — その後、 promise で包んだ Response
オブジェクトを返します。
これはもちろんただの HTTP レスポンスであり、実際の画像ではありません。response オブジェクトから画像を抜き出すには、 blob()
メソッドを使用する必要があります。 (Body
のミックスイン(訳注:phpのトレイトのようなものです。)として定義されていて、それらは Request
オブジェクトと Response
オブジェクトの両方に実装されています。)
付記: Body mixin は(httpリクエスト/httpレスポンスの)ボディのコンテンツをほかのmineタイプとして使用する似たようなメソッドを提供しています。詳細は Body セクションをご覧ください。
objectURL
は、 Blob
から抽出されたものから作られて、その後、img
要素に挿入されます。
Fetch リクエストは、検索したリソースからの指示よりも CSP の connect-src
ディレクティブによって制御されます。
リクエストにオプションを適用する
fetch()
メソッドには 2 つ目の引数を適用することもできます。多数の設定をコントロールすることのできる初期化オブジェクトです。
var myHeaders = new Headers(); var myInit = { method: 'GET', headers: myHeaders, mode: 'cors', cache: 'default' }; fetch('flowers.jpg',myInit) .then(function(response) { return response.blob(); }) .then(function(myBlob) { var objectURL = URL.createObjectURL(myBlob); myImage.src = objectURL; });
全ての設定可能なオプションや詳細な説明を見るには fetch()
を参照してください。
fetch が成功したかチェックする
ネットワークエラーに遭遇した際、 fetch()
promise は TypeError
を返して reject 状態になります。ネットワークエラーには、パーミッションに関する問題などが当たります。といっても 404 はネットワークエラーを構成しません。fetch() が成功したかどうかの明確な判定をするには、promise が解決したかどうか、その後 Response.ok
プロパティが true を返しているかなどを確認します。次のようなコードになるでしょう。
fetch('flowers.jpg').then(function(response) { if(response.ok) { response.blob().then(function(myBlob) { var objectURL = URL.createObjectURL(myBlob); myImage.src = objectURL; }); } else { console.log('Network response was not ok.'); } }) .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,myInit) .then(function(response) { return response.blob(); }) .then(function(myBlob) { var objectURL = URL.createObjectURL(myBlob); myImage.src = objectURL; });
fetch()
メソッドの引数と全く同じ引数を Request()
に適用させることができます。 また、リクエストオブジェクトのコピーを作成するためにすでに存在するリクエストオブジェクトを渡すこともできます。
var anotherRequest = new Request(myRequest,myInit);
これは、リクエストとレスポンスのボディを 1 つのみ使用しているので、大変役立ちます。必要であれば、init
オプションを変化させながらリクエスト / レスポンスを再利用できるようにコピーします。
付記: clone()
メソッドを利用してコピーを生成することもできます。これには、ほかのコピーメソッドと若干異なる意味があります — 古いリクエストのボディがすでに読み込まれていた場合、前者は失敗しますが、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.getAll("X-Custom-Header")); // ["ProcessThisImmediately", "AnotherValue"] myHeaders.delete("X-Custom-Header"); console.log(myHeaders.getAll("X-Custom-Header")); // [ ]
いくつかの操作は ServiceWorkers
でしか役立ちませんが、ヘッダーを操作するためのより良い API を提供しています。
全ての Header メソッドは有効な HTTP ヘッダーではない名前が渡されたとき TypeError を投げます。immutable ガード(下記を参照)がかかっている場合も、 TypeError を投げます。もしくはエラーを投げずに失敗します。例を見てください:
var myResponse = Response.error(); try { myResponse.headers.set("Origin", "https://mybank.com"); } catch(e) { console.log("銀行のふりをしないで下さい!"); }
ヘッダーの良い使用方法としては処理を行う前に、コンテンツタイプが正しいかどうか判定する等の使い方があります。例:
fetch(myRequest).then(function(response) { var contentType = response.headers.get("content-type"); if(contentType && contentType.indexOf("application/json") !== -1) { return response.json().then(function(json) { // process your JSON further }); } else { console.log("Oops, we haven't got JSON!"); } });
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() promise が解決(resolve)されたときに返り値として渡されます。
Response オブジェクトは私たち開発者の手によって動的に作ることもできます。これは ServiceWorkers
内において非常に役立ちます。例えばリクエストを受け取ったときに respondWith()
メソッドによってカスタマイズされたレスポンスを返すようなときに役立ちます。
var myBody = new Blob(); addEventListener('fetch', function(event) { event.respondWith( new Response(myBody, { headers: { "Content-Type" : "text/plain" } }) ); });
Response()
コンストラクタはオプションとして 2 つの引数をとることができます — レスポンスボディと初期化オブジェクト(Request()
が受け取れるものと似ています。)です。
下記はどんなレスポンスオブジェクトでも共通で使用できるレスポンスプロパティです:
Response.status
— HTTP ステータスコードの整数値(デフォルト値は 200)Response.statusText
— HTTP ステータスコードのメッセージと一致する文字列 (デフォルト値は "OK")Response.ok
— 上述の例で使用したように、これは HTTP ステータスコードが 200 から 299 のうちに収まってるかどうかのショートハンドです。これはBoolean
を返します。
付記: 静的メソッド error()
は単純にエラーレスポンスを返します。同様にredirect()
メソッドも 指定した URL にリダイレクトするレスポンスを返します。これらは Service Workers にのみ関連しています。
Body
リクエストもレスポンスもボディを持っています。body は以下のタイプのいずれかのインスタンスです。
ArrayBuffer
ArrayBufferView
(Uint8Array などの TypedArray)Blob
/File- 文字列
URLSearchParams
FormData
Body
mixin は Request
やResponse
に実装されていて、コンテンツを抜き出すために以下のメソッドが定義されています。これらはすべて最終的に実際の中身を返す promise を返します。
これらは非テキストデータを XHR よりはるかに楽に扱うことができます。
Request ボディは、body パラメータを渡すことによって設定することができます。
var form = new FormData(document.getElementById('login-form')); fetch("/login", { method: "POST", body: form })
Both リクエストや Body レスポンス(それと fetch() 関数の拡張)自動的にコンテンツタイプを決定しようとします。Request もまた自動で Content-Type ヘッダーが設定されます。
仕様書
仕様 | ステータス | コメント |
---|---|---|
Fetch | 現行の標準 | 初期定義 |
ブラウザ実装状況
機能 | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari (WebKit) |
---|---|---|---|---|---|
基本サポート | 42 41 behind pref |
39 (39) 34 behind pref |
未サポート |
29 |
未サポート |
機能 | Android | Firefox Mobile (Gecko) | Firefox OS (Gecko) | IE Phone | Opera Mobile | Safari Mobile | Chrome for Android |
---|---|---|---|---|---|---|---|
基本サポート | 未サポート | 未サポート | 未サポート | 未サポート | 未サポート | 未サポート | 未サポート |