Node-REDでRaspberry Piをapiサーバーにする時はクロス オリジン リソース共有の設定をしよう

Raspberry Pi zero wh
Raspberry PiのOS RaspbianにはNode-REDというjavascriptのプログラミングツールが入っています。これで簡単にWEBサービスが作れます。

Raspberry Piでapiサービスを動かしてみようと思った時の基本的な流れのメモです。


今回も私のメモ書きです。
Raspberr Piでapiサービスを動かす前にRaspberry Piをインターネット上に公開しなければなりません。最近はsslでhttps接続にしないとなりませんね。この辺の話は省きます。
公開できたとして、apiサービスを作る時の基本設定を紹介します。

apiサービスを作ろう

apiサービスと言ってもやってることは簡単です。postメソッドを受けたら適当な情報を返すだけです。極めてシンプル。
Node-REDのフローを書けばこんな感じです。
api基本フロー
ポストを受けたら何らか処理をしてレスポンスを返すだけです。
返すデータをjsonにすればJSONPサービスになってクロスドメイン制約も受けずブログパーツも作り放題・・・

Node-REDのレスポンスを受け取れない

簡単なので早速試そうとBloggerブログでRaspberry Piのアドレスを指定しjsonデータを表示させるスクリプトを置きました。
早速公開して見てみますが何も表示されません。キャッシュのせいかな?とブラウザのキャッシュをクリアしてみますが何も表示されません。
これはコードの間違えかと思い、ブラウザでエラーを確認すると次のメッセージがありました。
No 'Access-Control-Allow-Origin' header is present on the requested resource.

CORS(Cross-Origin Resource Sharing)

クロス オリジン リソース共有という仕組みでレスポンスを拒否しているのが原因です。詳しいことは他のサイト様へお任せです。
どこの誰かもわからない所からデータを要求されて無条件にデータを送信する事がないようになっています。

という事でhttp responseノードへ許可するサイトを教えれば良いのです。

httpレスポンスヘッダーに要素を追加する

やり方は簡単です。
http responcseノードのヘッダに要素を追加しておけば良いのです。ダブルクリックしてノード編集画面にヘッダーの項目を追加します。
次の二つを設定しておきます。
Access-Control-Allow-Origin には * を、
Access-Control-Allow-Methods には POST, GET, OPTIONS
を設定します。クライアントによっては他にも要素を追加しなくてはならないようですが、私は詳しくないので問題があったら検索して追加してください。

簡単にはこれだけで動くようになります。
しかし、どこからの要求でもデータを返す事になります。自分のブログのソースを見られればapiサーバーのアドレスがわかり、他の人のブログでもデータを要求できるしデータを渡してしまいます。一般サービスを作る場合には良いでしょうが、知らないところから大量のアクセスがあっても困ります。

そんな時はAccess-Control-Allow-Originに"*"ではなく自分のブログのURLを指定します。私のブログの場合は"https://blog-tips-z.blogspot.jp"にすると私のブログ以外からの要求は拒否する事になります。
ブログのURLと書きましたが、正確にはoriginに設定されているURLを設定しなくてはなりません。

apiサービスの要求を受けるhttp inノードの出力を見るとoriginが判ります。デバッグノードで"msg.req.headers.origin"の値を見ます。これがapiのリクエストをしてきたドメインという事です。

Google Blogger用にAccess-Control-Allow-Originを返す

私のブログはGoogle Bloggerを使っています。すると少し困った事があります。
Google Bloggerでは閲覧する国のトップドメインへ自動的にリダイレクトされてしまいます。
私のブログの場合、本来は
"https://signal-flag-z.blogspot.com"
というURLになるのですが日本で見る場合は
"https://signal-flag-z.blogspot.jp"
へリダイレクトされます。見る人の国によって"uk"とか"fr"とかに変わってしまいます。
そしてAccess-Control-Allow-Originの値は一つのoriginしか書けないようなのです。

このままでは"*"にしてどこからでもアクセスできるようにするしかありません。ちょっと嫌ですよね。こんな時はAccess-Control-Allow-Originの値を動的に設定します。

http resposeノードの入力にmsg.headersがあるとヘッダーとして返してくれます。
そこでhttp responseノードの前にfunctionノードを置いてjavascriptでデータを追加します。
例えば、
var origin = msg.req.headers.origin||"";
if(origin.match(/https:\/\/signal-flag-z.blogspot.\w\w\w?/)){
  msg.headers = {};
  msg.headers["Access-Control-Allow-Origin"] = origin;
  msg.headers["Access-Control-Allow-Methods"] = "POST";
} else {
  msg.statusCode = 404;
}
とします。
msg.reqにはhttp inノードで接続元情報が入っています。msg.req.headers.originの値が自分のブログのURLか判断し、そうならばAccess-Control-Allow-Originの値とします。
もしも自分のブログからでなければステータスコードを404にして居ないふりをします。

ついでにAccess-Control-Allow-Methodsの方はPOSTのみに応答するようにしています。こちらは使い方によって変えてください。

まとめ

便利なサービスが無くなったり有料になったりしていますので、自分が使いやすいサービスでも作ろうかと試行錯誤しています。
Node-REDを使うと簡単にweb上の情報へアクセスできます。インターネットの情報を集めるだけならすぐにできます。

集めた情報を外へ出そうとすると・・・最初につまづくのが今回の記事の内容だと思います。その前にhttps接続にするのも厄介でしけど。

コメント

最近のコメント

Threaded Recent Comments will be here.