Firebase Hostingを使ったサイトで、一部のパス(/api以下等)へのリクエストを別サーバーに投げられる仕組みを考えた。
別サーバーでCloud Functions(Node.js)で出来ないことをしたかった。
結果として動いてしまったけどなぜこんなことしてるのか分からなくなってきたのでまず整理。
1、アプリケーション概要
フロントエンド
Vue.jsでビルドしたSPA(Firebase Hostingで配信)
2、動機
上記構成を普通につくるとホスト名やSSL証明を分ける必要があり、下記のデメリットが発生する
なのでhttps://{firebase hostingのURL}/api等に来たリクエストを、そのままバックエンドにプロキシすることができたらいいなぁと思った。
3、手順
1、Firebase Functionsでリクエストをプロキシする関数を作る
まずFunctionsのinitは公式通りに行う。
https://firebase.google.com/docs/functions/get-started?hl=ja
今回はHTTPがトリガーなので下記を理解する
HTTP リクエスト経由で関数を呼び出す | Firebase
で、さっそく作り始める。
expressでプロキシを作るのは、ぐぐったら今回にぴったりなパッケージが見つかった。
www.npmjs.com
とりあえずindex.jsはこんな感じになった.
最後でexposeしているapiProxyが名前として使われ、URLの一部にもなる。
functions/index.js
const functions = require('firebase-functions'); const proxy = require('express-http-proxy'); const app = require('express')(); const apiHost = 'your.api.example.com' app.use('/', proxy(apiHost)); exports.apiProxy = functions.https.onRequest(app);
あとでいろいろ必要になるとも思うけど6行でできてしまった
npmのインストール情報
package.json
] { "name": "functions", "description": "Cloud Functions for Firebase", "scripts": { "lint": "eslint .", "serve": "firebase serve --only functions", "shell": "firebase functions:shell", "start": "npm run shell", "deploy": "firebase deploy --only functions", "logs": "firebase functions:log" }, "dependencies": { "express": "^4.16.3", "express-http-proxy": "^1.2.0", "firebase-admin": "~5.12.1", "firebase-functions": "^1.0.3" }, "devDependencies": { "eslint": "^4.12.0", "eslint-plugin-promise": "^3.6.0" }, "private": true }
これで
firebase deploy
して成功すると下記のようなURLが表示されるのでアクセスしてみる
https://{region}-{project-id}.cloudfunctions.net/apiProxy/
まだGKEではDjangoをデバックで動かしているのでこんな感じで出た。
ちゃんとつながった。
あとはこれをFirebase Hosting側に設定する
firebase.json
{ "hosting": { "public": "dist", "ignore": [ "firebase.json", "**/.*", "**/node_modules/**" ], "rewrites": [ { "source": "/api/**", "function": "apiProxy" }, { "source": "**", "destination": "/index.html" } ] }, "functions": { "predeploy": [ "npm --prefix \"$RESOURCE_DIR\" run lint" ] } }
/api/**をapiProxyにリライトする設定を追加した。
これをまたdeployして、今度はhosting側のURLに/apiをつけてアクセスしてみる
https://{project-id}.firebaseapp.com/api/
同じくつながってた。
デメリット
レスポンスが遅くなる
簡略化して書くと
GKE → ロードバランサー → ユーザー
で済んでいたのが
GKE → ロードバランサー → Firebase Functions → Firebase Hosting → ユーザー
となるので、遅い。
しかもやっかいなのがFirebase Functionsのリージョンは今のところ選択できないため、usになってしまい、さらに遅くなる。
上記のテストでもレスポンスが600ms程度かかっていた。
結果としてこの遅さは致命的なので、今回は使うことはなさそう。
レスポンスの遅さが気にならないものや、何としても同一ドメインで別サーバーで処理をさせたい場合には使い道があるかも。