Web API のプロトタイプを Firebase Functions の http ハンドラーを使って実装して、それを JavaScript から呼び出したら、 No 'Access-Control-Allow-Origin' header のエラーが出たので、それに対応した手順を書きます。
Firebase Functions を REST API のように 即時に応答を要求する用途 に使うのはほとんどの場合間違っています。一般的に、クラウドプラットフォームで提供される "Functions" と呼ばれる機能は、起動は遅いと考えたほうがよいです。
次のような say
関数を作りました、TypeScript で。
import * as functions from 'firebase-functions';
export const say = functions.https.onRequest((request, response) => {
response.send("Hello from Firebase!");
});
サンプルまんまです。
firebase serve
をして、ローカルで動作させると、
http://localhost:5001/<project名>/us-central1/say
のような URL で起動できます。
これを呼び出す HTML を次のように書きました。
この index.html
は Firebase Hosting に配置するので、 public
ディレクトリに置きます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Firebase Hosting</title>
<script type="text/javascript">
function loadHello() {
var label = document.getElementById("label");
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState == 4) {
if (req.status == 200) {
label.innerHTML = req.responseText;
}
} else {
label.innerHTML = "通信中...";
}
}
req.open('GET', 'http://localhost:5001/<プロジェクト名>/us-central1/say', true);
req.send(null);
}
</script>
</head>
<body onLoad="loadHello()">
<H1>Firebase Hosting</H1>
<div id="label">loading..</div>
</body>
</html>
こちらも firebase serve
しているときに http://localhost:5000/
でアクセスできます。
index.html
は、読み込み時に Functions の /say
を呼び出して、そのレスポンスを id=label
に表示する、というものですが、読み込み時に Console にエラーが出ます。
Failed to load http://localhost:5001/xxxx/us-central1/say:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:5000' is therefore not allowed access.
よくあるやつです。
Functions を CORS に対応させる(別ドメインからの呼び出しを許可する)には、expressjs/cors: Node.js CORS middleware という node.js 用ライブラリを使います。今回は TypeScript なので、これの type definitions である
を使います。
まずは cors と @types/cors をインストールします。
npm install --save cors
npm install --save-dev @types/cors
functions/package.json
は次のようになっています。
{
"name": "functions",
"scripts": {
"lint": "tslint --project tsconfig.json",
"build": "tsc",
"serve": "npm run build && firebase serve --only functions",
"shell": "npm run build && firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"main": "lib/index.js",
"dependencies": {
"cors": "^2.8.4",
"firebase-admin": "~5.12.1",
"firebase-functions": "^1.0.3"
},
"devDependencies": {
"@types/cors": "^2.8.4",
"tslint": "^5.8.0",
"typescript": "^2.5.3"
},
"private": true
}
続いて Functions を次のように書き換えます。
import * as functions from 'firebase-functions';
import * as corsLib from 'cors';
const cors = corsLib();
export const say = functions.https.onRequest((request, response) => {
return cors(request, response, () => {
response.send("Hello from Firebase!");
})
});
cors を import して関数として実行。
さらに onRequest
の中を、 cors(req, res, ()=>{ })
で包んじゃいます。
これで html を表示させると、エラーは消え、次のような画面が表示できます。