jQuery.ajax()の代替としてFetch APIをざっくり使ってみる
jQueryを使わずにAjaxをしたくて、とはいえ生のXHR(XMLHttpRequest )を扱うのはめんどくさいっていうときに、Fetch APIを使ってみました。そのとき調べたことの覚え書きです。
Fetch APIって?
ここに、Jxck先生のすばらしい記事があります。
正直ぜんぜん理解できてないのですが(🙇)、ものすごくざっくりいうと、
みたいな感じなのかなと思いました。
ちなみに、先の記事では単なるXHRの代わりじゃないと記載されてるので、FetchとかFetch APIの理解にはそちらを読んでもらった方がいいかと思います。。
ブラウザサポート状況
Can I use... Support tables for HTML5, CSS3, etcを見る限り、IEとSafari、iOS Safari以外は対応してるみたいです。
私の場合はそれでもよかったので使ってないのですが、pollyfilもあるみたいです。
GET
次のような感じでGETができます。簡単!
fetch(url) .then(response => { return response.text(); }) .then(body => { document.body.innerHTML = body; });
先述したとおり、Fetch APIではPromiseが返ってくるため、then()
で繋げて書いていくことができます。
レスポンスは、以下のいずれかの形式で取得できます。
- プレーンテキスト :
response.text()
- JSON :
response.json()
- ArrayBuffer :
response.arrayBuffer()
- Blob :
response.blob()
POST
POSTする場合は、fetch()
の第二引数にオプションでmethod: 'POST'
を指定するだけです。$.ajax()
っぽい!
fetch(url, { method: 'POST', body: new FormData(document.getElementById('form')) }) .then(response => { return response.json(); }) .then(json => { ... });
サーバーに値を渡すには、body
オプションに指定できます。
クロスオリジン通信
オリジンが異なる(別ドメインの)サーバーと通信したい場合は、次のようにCORSを使います。
1. クライアント側で、fetch()
のmode
オプションに'cors'
を指定する
fetch(url, { mode: 'cors' }) .then(response => { ... });
2. サーバー側でリクエストヘッダのOrigin
をチェックする
GET /api HTTP/1.1 Origin: http://xxx.com
3. サーバー側でレスポンスヘッダにAccess-Control-Allow-Origin
を追加する
HTTP/1.1 200 OK Access-Control-Allow-Origin: http://xxx.com
これで、クロスオリジン通信が可能になります。
Access-Control-Allow-Origin: *
のAPIの場合は1.の指定だけでできると思います。
Cookieを許可
Cookieを許可するには、次のように指定します。
1. クライアント側でfetch()
のcredentials
オプションに'include'
を指定する
fetch(url, { mode: 'cors', credentials: 'include' }) .then(response => { ... });
2. サーバー側でレスポンスヘッダにAccess-Control-Allow-Credentials: true
を追加する
HTTP/1.1 200 OK Access-Control-Allow-Origin: http://xxx.com Access-Control-Allow-Credentials: true
独自のリクエストヘッダを追加
とあるAPIを利用するときに、独自のリクエストヘッダを追加して通信する必要がありました。その場合、次のように指定できます。
1. クライアント側でfetch()
のheaders
オプションに、オブジェクトの形式で独自ヘッダーを指定する
fetch(url, { method: 'GET', mode: 'cors', headers: { 'X-MyRequest': 'hoge' } }) .then(response => { ... });
2. サーバー側でプリフライトリクエストのリクエストヘッダを確認する
OPTIONS /api HTTP/1.1 Origin: http://xxx.com Access-Control-Request-Method: GET,POST,HEAD,OPTIONS Access-Control-Request-Headers: X-MyRequest
3. 許可する場合は、サーバー側からレスポンスヘッダを返す
HTTP/1.1 200 OK Access-Control-Allow-Origin: http://xxx.com Access-Control-Allow-Methods: GET Access-Control-Allow-Headers: X-MyRequest
4. 実際のリクエストがクライアントからサーバーに送られる
サーバー側からAccess-Control-Allow-Methods
とAccess-Control-Allow-Headers
で許可されたものしか送れないという仕組みのようです。
独自のレスポンスヘッダを読み出す
まず最初に、ダメだった方法を。
1. サーバー側から独自のレスポンスヘッダを追加したレスポンスを返す
HTTP/1.1 200 OK X-MyResponse: hoge
2. クライアント側でresponse.headers.get()
にて取得しようとするもできない
fetch(url, { method: 'GET', mode: 'cors' }) .then(response => { console.log(response.headers.get('X-MyResponse')); });
この場合、セキュアではないヘッダにアクセスしようとしたと見なされてアクセスが許可されなかったようです。
なお、以下のヘッダには、問題なくアクセス可能です。
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
そのため、次のようにする必要があるようです。
1. サーバー側でアクセスを許可する独自ヘッダをAccess-Control-Expose-Headers
で指定する
HTTP/1.1 200 OK Access-Control-Allow-Origin: http://xxx.com Access-Control-Allow-Methods: GET,POST,HEAD,OPTIONS Access-Control-Allow-Headers: X-MyRequest Access-Control-Expose-Headers: X-MyResponse
2. クライアント側でresponse.headers.get()
にて取得する
fetch(url, { method: 'GET', mode: 'cors' }) .then(response => { console.log(response.headers.get('X-MyResponse')); });
サーバー側のエラーの処理
fetch()
では、サーバー側でエラーが起こってもレスポンスはreject()
されません。つまりcatch()
できないわけです。
では、どういう場合にreject()
されるのかというと、ネットワークエラーの場合のみのようです。そのため、サーバーエラーの処理は、then()
の中でresponse.ok
をチェックする必要があります。
fetch(url) .then(response => { if (!response.ok) { throw Error(response.statusText); } return response; }) .then(response => { ... }) .catch(err => { ... });
まとめ
jQuery.ajax()
が使えるときはそっちのが安心感あるけど、個人プロジェクトで少し触ってみる程度ならよいのかも?
※実際に使ってみたのは1年以上前だし、内容が古いかもしれないです。