Node-RED の HTTP ノード(HTTP in ノードと HTTP Response ノード)を使うと簡単に REST API を作ることができて便利です。自分もデータベースへの CRUD 操作を作る際などによく使っています。

が、この方法で作った REST API にはクロスオリジン制約(いわゆる CORS)が付きます。例えば https://xxxx.mybluemix.net/ というホストで Node-RED を動かしている場合、作成する REST API のエンドポイント URL は https://xxxx.mybluemix.net/getdata とかになるわけですが、この API を AJAX などのブラウザ上の JavaScript から呼ぼうとすると、同一サーバー上の( https://xxxx.mybluemix.net/**** というアドレスのページの) HTML からでないとエラーになってしまうのでした。サーバーサイドのプログラムから実行することはできるのですが、ブラウザ上の JavaScript から実行するには同一ホストからでないといけない、という制約が付くのでした(ま、この制約自体はある方が一般的ですけど)。

この CORS の制約を外して、外部の(https://xxxx.mybluemix.net/ 以外の)ページやローカルシステム上ページの JavaScript からでもこの API を呼べるようにする、そのための設定方法と手順を紹介します。

まず Node-RED で REST API を作成します。今回は以下のような HTTP in ノードと、Function ノードと、HTTP Response ノードをつなげただけのシンプルな REST API を用意しました:
2018101801


HTTP in ノードの設定は以下のように GET /corstest で呼び出せるような設定にしています:
2018101802


Function ノードは以下のような JavaScript を記述し、実行時のタイムスタンプ値を JSON で返す、という関数にしています:
msg.payload = { timestamp: ( new Date() ).getTime() };
return msg;

2018101803


HTTP Response ノードにはこの段階では特に手を加えません。配置しただけの状態のまま接続してデプロイします。これで REST API 側は準備できました。

次に HTML ファイルを用意します。今回はサーバー上ではなくローカルシステム上に以下のような内容の HTML ファイルを用意しました:
<html>
<head>
<meta charset="utf8"/>
<title>CORS テスト</title>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
function corstest(){
  $.ajax({
    type: 'GET',
    url: 'http://xxxx.mybluemix.net/corstest',  // 上記で作った REST API のエンドポイントURL
    success: function( result ){
      console.log( result );
    },
    error: function( err ){
      console.log( "error" );
      console.log( err );
    }
  });
}
</script>
</head>
<body>
<input type="button" value="CORS" onClick="corstest()"/>
</body>
</html>

この HTML ファイルをブラウザから(Ctrl+O などでファイルを指定して)開くと、"CORS" と書かれたボタンが1つだけ配置されたページが開きます:
2018101807


HTML を見るとわかるのですが、このボタンをクリックすると GET https://xxxx.mybluemix.net/corstest という API が実行され、成功するとその結果が、失敗すると "error" というメッセージに続いてエラーメッセージが、それぞれ表示される内容になっています。なおこのエンドポイント URL の xxxx 部分が実際に作成した Node-RED 環境のホスト名にあわせて変更してください。


ブラウザのコンソールを開いて(F12)、この CORS ボタンをクリックします。現状は CORS の対策を何もしていないので当然のようにエラーになります。エラーの内容はコンソールに表示され、原因はクロスオリジン制約のようです。これをどうにかしたい、というのが今回のテーマです:
2018101804


では、この REST API の実行が成功するよう API 側をカスタマイズします。Node-RED のフロー画面に戻って、HTTP Response ノードをダブルクリックして編集状態にします。そして「ヘッダ」と書かれた欄の「+追加」という部分をクリックし、HTTP Response ヘッダを追加します。そして左側(ヘッダ名)の欄には Access-Control-Allow-Origin と、そして右側(ヘッダ値)の欄には *(どのドメインからのリクエストでも許可するの意)とそれぞれ入力し、最後に「完了」→「デプロイ」します:
2018101805


この設定によって REST API の実行結果を返す際のヘッダに Access-Control-Allow-Origin: * という一行が追加されて返るようになり、このヘッダによってクロスオリジンが許可されているとブラウザ側からも判断され、期待通りの結果が得られるようになります。再度 CORS ボタンをクリックして REST API を実行するとコンソールにはリクエストが成功した時の結果が表示されるようになりました:
2018101806


CORS の制約を理解した上で外す(あるいは特定のドメイン名やホスト名を指定した上で許可する)、という点に注意してください。