マイコン温度通知システムの製作10 超過温度のLINE通知3

Firebase Cloud Functionsで関数を作って呼び出す場合の関数の特徴

普通のプログラムでは簡単に関数を作って呼び出せますが、Firebase Cloud Functionsで関数を作って呼び出す場合、以下のように必ず関数が何らかのトリガーによって呼び出される形で設計する必要があります。

// HTTPリクエストを受け取るエンドポイントを定義
exports.sendMessageToLineGroup = functions.https.onRequest((req, res) => {
  // POSTリクエストからグループIDとメッセージテキストを取得
  const groupId = req.body.groupId;
  const messageText = req.body.text;

関数をデプロイしてもFirebaseのFunctionsの画面で確認できない

複数の関数作成しデプロイしましたが、ある関数がFirebaseのFunctions画面で確認できませんでした。

そこでブラウザのキャッシュをクリアしましたが、それでも確認できませんでした。

デプロイ時のログに以下の箇所がありました。

⚠ functions: package.json indicates an outdated version of firebase-functions. Please upgrade using npm install –save firebase-functions@latest in your functions directory.

このため、以下のコマンドでfirebase-functionsのバージョン確認と更新を行いました。

npm show firebase-functions version
npm install firebase-functions@latest --save

しかし、更新したにもかかわらず上記のpackage.jsonファイルが更新されていないというログが再び表示されました。

これについて、上記の更新コマンドを実行したディレクトリが誤っていました。

正しくはfunctions配下で実行するべきなのに、その上位のfirebaseディレクトリでコマンドを実行していました。

そのため、functions配下で更新コマンドを実行したところ、エラーログは出なくなりました。

なお、上記のためfirebaseディレクトリに以下の不要なファイル、フォルダが存在していたので削除しました。

node_modules
package-lock.json
package.json

しかし、エラーログは出なくなったものの、やはり管理画面で関数を確認できませんでした。

元々Firebaseの画面では確認できない関数だった

色々と調べましたが、結局、Firebaseの画面で確認できないと悩んでいた関数は元々確認できないものでした。

以下、chatGPTより。

■ 確認できる関数の種類
・HTTPトリガー関数: functions.https.onRequest や functions.https.onCall で定義される関数。これらは外部からHTTPリクエストを通じて直接呼び出すことができます。

・バックエンドトリガー関数: Firestoreのドキュメント更新、Firebase Authenticationのユーザー作成・削除、Firebase Storageへのファイルアップロードなど、Firebaseの他のサービスによってトリガーされる関数。これらは特定のイベントが発生したときに自動的に実行されます。

■ ブラウザで確認できない関数の理由
あなたが提供した最初のコード例では、getLineGroupId 関数は普通のJavaScript関数として定義されており、外部から直接アクセス可能なFirebase Cloud Functionsの形式で公開されていません。この関数は内部的に使用するためのもので、HTTPトリガーや他のFirebaseサービスのトリガーによって実行されるわけではないため、Firebase Functionsのブラウザ画面には表示されません。

という訳で、functions.https.onRequest や functions.https.onCall で定義されていない普通の関数はブラウザでFirebaseの画面から確認できないということでした。

また、トリガー関数でもindex.jsで記述していないと、同じくブラウザのFirebaseのFunctions画面から確認できません。

HTTPリクエストを送信して動作でエラー(Internal Server Error)が出る

HTTPリクエストで以下のエラーが発生しました。

curl -X POST https://us-central1-temperature-XXX.cloudfunctions.net/xxxxx \-H "Content-Type: application/json" \
-d '{"groupId": "xxx", "text": "textdata"}'
Internal Server Error%

・Firebaseのログ

insertId: "65eb496300025805e43b2579"
labels: {2}
logName: "projects/temperature-XXX/logs/cloudfunctions.googleapis.com%2Fcloud-functions"
receiveTimestamp: "2024-03-08T17:22:43.159967717Z"
resource: {2}
textPayload: "(node:1) Warning: Accessing non-existent property 'sendMessageToLineGroup' of module exports inside circular dependency"
timestamp: "2024-03-08T17:22:43.153605Z"

このエラーは循環依存で、あるファイルでインポートしている関数があったとして、その関数もそのファイルをインポートして、相互で読み込んでしまいエラーになる、ということでした。

そのためインポートを削除しました。

404 Page not found エラーが出る

またエラーが出ました。

curl -X POST https://us-central1-temperature-XXX.cloudfunctions.net/xxxxx \-H "Content-Type: application/json" \ -d '{"groupId": "xxx", "text": "textdata"}'
<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>404 Page not found</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Page not found</h1>
<h2>The requested URL was not found on this server.</h2>
<h2></h2>
</body></html>

・Firebaseのログ

insertId: "65eb496300037d8dfd3f17bc"
labels: {3}
logName: "projects/temperature-measurement-b3fcd/logs/cloudfunctions.googleapis.com%2Fcloud-functions"
receiveTimestamp: "2024-03-08T17:22:43.492678198Z"
resource: {2}
textPayload: "Failed to send message: TypeError: sendMessageToLineGroup is not a function"
timestamp: "2024-03-08T17:22:43.228749Z"
trace: "projects/temperature-measurement-b3fcd/traces/7b7cc2b0a789930b97af5bce48f480ed"

chatGPTによる回答は以下になります。

エラーメッセージ「404 Page not found」は、指定されたURLに対応するリソースがサーバー上に存在しないことを示しています。

エラーメッセージ “Failed to send message: TypeError: sendMessageToLineGroup is not a function” は、testFunction が sendMessageToLineGroup 関数を呼び出そうとした際に、その関数が見つからないか、関数として認識されていないことを示しています。

ということで、該当の箇所を修正しましたが、それでも同じ404エラーが出ました。

その原因を探ると、関数がデプロイしたのに公開されていない(FirebaseのFunctions画面に載らない)のが原因でした。それは上記で書きましたが、index.jsに記述することで解決できました。

もう1つの404エラー

また別件で同じ404エラーが出ました。

原因は、httpリクエストになっていないためでした。

・誤りのコード

exports.sendMessageToLineGroup = async (req, res) => {

・正しいコード

const functions = require("firebase-functions");
exports.testSendMessage = functions.https.onRequest(async (req, res) => {

403 Forbidden エラーが出る

HTTPリクエストをしたところ、以下のエラーが起きました。

curl -X POST -H "Content-Type: application/json" -d '{"text":"YOUR_MESSAGE_TEXT_HERE", "groupId":"XXX"}' https://us-central1-temperature-XXX.cloudfunctions.net/XXX

<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>403 Forbidden</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Forbidden</h1>
<h2>Your client does not have permission to get URL <code>/XXX</code> from this server.</h2>
<h2></h2>
</body></html>

関数にアクセスする権限が無いため起きているようです。

https://console.cloud.google.com/functions/ にアクセスします。

アクセス権限を変更する関数を選択し、「権限」をクリックします。

「プリンシパル」を追加をクリックします。

新しいプリンシパルに「allUsers」、ロールに「Cloud Functions 起動元」を入力し保存します。

一般公開アクセスを許可を選択します。

これによりHTTPリクエストコマンドはエラーにならず実行できるようになりました。

データベースからデータ取得で合致しているのに取得できず意図する動作にならない

以下のように、macAddressを渡してデータベースから合致するLINE IDを取得するコードをデプロイしました。

async function getLineGroupId(macAddress) {
  console.log("getLineGroupId start");
  const associationTableRef = db.collection("associationTable");

  // 全ドキュメントを取得してログに出力する
  const allDocsSnapshot = await associationTableRef.get();
  allDocsSnapshot.forEach((doc) => {
    console.log(`Document ID: ${doc.id}, macAddress: ${doc.data().macAddress}`);
  });

  // データベースからMACアドレスが等しいデータを取得
  const snapshot = await associationTableRef
      .where("macAddress", "==", macAddress).get();

  // MACアドレスが合致するデータが存在しない場合の表示
  if (snapshot.empty) {
    console.log("該当するデータが見つかりません。");
    return null;
  }

・上記の関数を呼び出す関数を以下のコマンドで実施

curl -X POST -H "Content-Type: application/json" -d '{"text":"YOUR_MESSAGE_TEXT_HERE", "macAddress":"XXX"}' https://us-central1-temperature-XXX.cloudfunctions.net/testFunction

・Firebaseのログ

{
  "textPayload": "Document ID: data1, macAddress: XXX",
  "insertId": "65ebc8370009b0ea2d9195cd",
  "resource": {
    "type": "cloud_function",
    "labels": {
      "region": "us-central1",
      "function_name": "testFunction",
      "project_id": "temperature-measurement-b3fcd"
    }
  },

Firebaseのログもコマンドで送信したMACアドレスも同じなのに、合致したらデータベースから値を呼び出すはずができていないようです。

色々と試した結果、データベースに記述のフィールド名を間違っていました。

lineGroupId」とするべきところを、「lineGropuId」という誤字のため、エラーが出ていました。

HTTPリクエストのコマンドでタイムアウトしてしまう

別の関数について、以下のコマンドを実行したところ、タイムアウトしてしまいました。

curl -X POST https://us-central1-temperature-XXX.cloudfunctions.net/testFunction02 -H "Content-Type: application/json" -d '{"macAddress":"XXX"}'
upstream request timeout%

これはFirebase Cloud FunctionsでHTTPリクエストを処理する際、処理が完了したら必ずres.send(), res.json(), res.end()などを呼び出してクライアントにレスポンスを送信する必要があるものの、コードには記述されていなかったためでした。

タイトルとURLをコピーしました