[HTML5] Fetch API で GET/POST で通信する

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.oktrueになるのでこれを利用するか、もう少し厳密にチェックしたい場合には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

参考ページ