30歳からのプログラミング

30歳無職から独学でプログラミングを開始した人間の記録。

IE11 で API と非同期通信を行うためのコード

年に1回くらいは必要になりそうだけど絶対に忘れてしまうと思うので、検証済みのコードを自分用に記録しておく。

APIを叩くコードを、IE11でも動くように書く。
何らかの理由で Babel によるトランスパイルが出来ない、したくない状況を想定している。
基本的にスタティックなページだがサイトの更新情報だけAPIで取得して表示したい、というケースなど。

まずコードの全体像を載せる。

(function() {
  function apiRequest(method, endPoint, body, onSuccess) {
    var xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          onSuccess(JSON.parse(xhr.responseText));
        }
      }
    };

    xhr.open(method, endPoint);
    xhr.withCredentials = true;
    xhr.setRequestHeader('Content-Type', 'application/json');
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    xhr.send(body ? JSON.stringify(body) : null);
  }

  apiRequest(
    'POST',
    'http://api.example.com/login',
    {userName: 'admin', password: 'pass'},
    function(res) {
      console.log(res);
    }
  );
})();

この内容のファイルを<script src="./ie11.js" defer></script>という形で読み込ませれば、動く。
DOM操作などがある場合はHTMLのパースが終わってから読み込みたいので、念の為deferをつける。

参考: qiita.com

apiRequestに必要な情報を渡して呼び出すことで、リクエストが発生する。
console.log(res);の部分でapiRequestを実行すれば、リクエストの結果を受けてまた別のAPIを呼ぶ、ということも出来る。
それを繰り返すとどんどんコールバック地獄になっていくが。

以下、解説。

まず、グローバル汚染を防ぐために、無名関数を実行してそのなかで全ての処理を行う。
アロー関数は使えないので、無名関数もfunctionを使って定義する。以降も同様。

(function() {})();

fetchはIE11では使えないので、XMLHttpRequestオブジェクトのインスタンスを作りそれを使って非同期通信を行う。
letconstも使えないので、変数宣言は全てvar

var xhr = new XMLHttpRequest();

以降、このインスタンス(今回の例ではxhr)に対して設定や操作を行っていく。

まずonreadystatechange
これには、コールバック関数を渡す。この関数は、readyStateが変わる度に呼び出される。
readyStateは通信状態が変わっていく度に値が変わるが、通信が完了すると4になる。
なので、xhr.readyState === 4を条件にして、通信完了時の処理を書けばよい。
statusには、レスポンスのステータスコードが入っている。
今回は通信が成功したときにのみ処理を行うのでxhr.status === 200のときに、レスポンスを引数にしてonSuccessを実行している。

xhr.onreadystatechange = function() {
  if (xhr.readyState === 4) {
    if (xhr.status === 200) {
      onSuccess(JSON.parse(xhr.responseText));
    }
  }
};

ここらへんの詳しい説明は、MDNにまとまっている。

openで、HTTPメソッドとURLを指定する。

xhr.open(method, endPoint);

withCredentialstrueにすれば、クッキーの送受信も行われる。

xhr.withCredentials = true;

なお、CORSについては設定は不要。fetchではmode: 'cors'の設定が必要だったが、XMLHttpRequestでは何もする必要がない。

独自ヘッダを付与したい場合は、setRequestHeaderを使う。

xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');

sendで、実際にリクエストを送信する。引数が、リクエストボディの値になる。

xhr.send(body ? JSON.stringify(body) : null);

参考資料