Experiments Never Fail

Firebase Functions + TypeScript で CORS を使用する

Web API のプロトタイプを Firebase Functions の http ハンドラーを使って実装して、それを JavaScript から呼び出したら、 No 'Access-Control-Allow-Origin' header のエラーが出たので、それに対応した手順を書きます。

まず #

Firebase Functions を REST API のように 即時に応答を要求する用途 に使うのはほとんどの場合間違っています。一般的に、クラウドプラットフォームで提供される "Functions" と呼ばれる機能は、起動は遅いと考えたほうがよいです。

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 #

これを呼び出す 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/ でアクセスできます。

*No Access-Control-Allow-Origin エラー #

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 を使う #

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 を表示させると、エラーは消え、次のような画面が表示できます。

image.png

published at tags: Node.js TypeScript CORS Firebase