Ajaxによる通信は長きに渡りXMLHttpRequest(XHR)で書かれていましたが、HTML5からFetchAPIが実装されずいぶんとシンプルに記述することが可能になりました。今回は基本的な使い方についてまとめておきたいと思います。
基本的な使い方
GET
fetch()
に取得したいURLを指定するだけでGETによるリクエストが可能です。fetch()
はPromiseを返してくれますのでレスポンス内容を処理したい場合にはthen()
内で処理を行います。
以下の例はhttps://example.com/foo.json
へGETでリクエストを行い、返却されたJSONを処理する例です。
fetch("https://example.com/foo.json") .then((res)=>{ return( res.json() ); }) .then((json)=>{ // ここに何らかの処理 });
最初のthen()は何やってるの?
サーバからJSONだと言われて受け取ったデータですが、最初の時点では単なる「文字列」です。これを連想配列(ハッシュ)などに変換しJavaScript上で扱いやすくするための処理をここで行っています。thne()
が2つに分かれているのはres.json()
が非同期処理になるためです。
.then((res)=>{ return( res.json() ); })
なお.json()
の部分はサーバから受け取ったデータによって変更してやることになります。HTMLなどテキスト情報が返ってくる場合はtext()
、画像などバイナリの場合はblog()
やarrayBuffer()
となります。
- arrayBuffer();
- blob();
- formData();
- json();
- text();
以下はサーバからのデータをテキストとして受け取り、任意のキーワードが含まれるかカウントしています。
fetch("https://example.com/foo.html") .then((res)=>{ return( res.text() ); }) .then((text)=>{ let nyaan = text.match(/にゃーん/g); if( nyaan !== null ){ alert(`にゃーんが${nyaan.length}件含まれています`); } else{ alert("Nothing にゃーん"); } });
クエリーを指定する
クエリー(引数)を付けたい場合は、単純にURLの後ろに付加してあげます。エンコードをお忘れなく。
const id = encodeURIComponent("xxxxx"); const name = encodeURIComponent("太郎"); fetch(`https://example.com/foo.json?id=${id}&name=${name}`)
POST
fetch()
にオプションを付けることでPOSTによる通信も可能です。
以下はJSONをPOSTとして送付する例になります。
// サーバへ送りたいデータ const data = {foo:"bar"}; // FetchAPIのオプション準備 const param = { method: "POST", headers: { "Content-Type": "application/json; charset=utf-8" }, // リクエストボディ body: JSON.stringify(data) }; // paramを付ける以外はGETと同じ fetch("https://example.com/foo.json", param) .then((res)=>{ return( res.json() ); }); .then((json)=>{ // ここに何らかの処理 });
ファイルをアップロード
長くなったので記事を分けました。以下のページをご覧ください。 blog.katsubemakito.net
共通
エラー処理(通信時)
実行時エラーが発生した場合はcatch()
で補足することができます。とりあえず試してみたい場合はPCをオフライン、スマホは機内モードにすると挙動が確認できますよ。
fetch("https://example.com/foo.json") .then((res)=>{ return( res.json() ); }) .then((json)=>{ // ここに何らかの処理 }) .catch((error)=>{ // ここでエラー処理 })
なおcatch()
で補足できるのは通信時に発生したネットワーク的なエラーであって、Webサーバから404や500番代が返された場合は対象となりません。
エラー処理(400,500番代)
ファイルが無かった場合(404)や、サーバエラー側の障害(500)などを補足する場合は、もうひと手間かけて上げる必要があります。
次の例のようにステータスコードが200番台であればres.ok
がtrue
になるのでこれを利用するか、もう少し厳密にチェックしたい場合にはres.status
に具体的なステータスコードが入っているのでこれをチェック。最終的にこちらが望むステータスコードで無かった場合に例外を発生させることで、catch()
へと誘導することが出来ます。
fetch('https://example.com/foo.json') .then((res)=>{ if( ! res.ok ) { // 例外を投げるとcatch()へ行く throw new Error(`Fetch: ${res.status} ${res.statusText}`); } return( res.json() ); }) .then((json)=>{ console.log(json); }) .catch((error)=>{ console.error(error); });
Cookieを自動で送りたい
セキュリティの関係でFetchAPIではCookieが自動的にサーバへ送信されません。もし自動的に送信したい場合はオプションで指定する必要があります。
以下の例のようにcredentials
を追加するだけです。
const param = { credentials: "same-origin" }; fetch("https://example.com/foo.json", param)
credentials
に設定する値は以下の通り。基本的にはsame-origin
でしょうか。
値 | 説明 |
---|---|
omit | 一切送信しない(デフォルト) |
same-origin | 同じドメインの場合は送信する |
include | 異なるドメインでも送信する |
サンプル
GET
実行例
以下から実際のサンプルをお試しいただけます。 miku3.net
ソースコード
HTML
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Fetch API Sample1</title> <style> #jst{ text-decoration:underline; font-weight:bold; } #result{ display:none; } </style> </head> <body> <section> <h1>Fetch API Sample1</h1> <div id="nowloading"> ...サーバから時間を取得中 </div> <div id="result"> 現在の時間は <time id="jst"></time> です。 </div> </section> <script src="app.js"></script> </body> </html>
JavaScript
/** * [event] ページ読み込み完了時に実行 */ window.onload = ()=>{ const URL = "https://ntp-b1.nict.go.jp/cgi-bin/json"; // リクエスト先 //-------------------------------------- // 現在時間を取得する //-------------------------------------- fetch(URL) .then((res)=>{ if( ! res.ok ) { throw new Error(`Fetch: ${res.status} ${res.statusText}`); } return( res.json() ); }) .then((json)=>{ const sec = Number(json.st); document.querySelector("#jst").innerHTML = timeFormat(sec); // 表示を切り替える document.querySelector("#nowloading").style.display = "none"; document.querySelector("#result").style.display = "block"; }) .catch((error)=>{ alert("エラーが発生しました"); console.error(`[FetchAPI] ${error}, ${URL}`); }) } /** * UNIX TIMEを「YYYY-MM-DD hh:mm:ss」形式の文字列へ変換 * * @param {number} sec - UNIX TIME * @return {string} */ function timeFormat(sec){ const time = new Date(sec * 1000); // JSではミリ秒に直す必要がある return( time.getFullYear() + "-" + ("00" + (time.getMonth()+1)).slice(-2) + "-" + ("00" + time.getDate()).slice(-2) + " " + ("00" + time.getHours()).slice(-2) + ":" + ("00" + time.getMinutes()).slice(-2) + ":" + ("00" + time.getSeconds()).slice(-2) ); }
POST
実行例
以前書いた以下の記事で利用していますので、こちらを参考どうぞ。 blog.katsubemakito.net