首页 > 解决方案 > 从域调用时,Firebase 函数不执行

问题描述

我有一个使用 NodeJS 创建的带有 Firebase 后端的 React Web 应用程序。我使用 Firebase 函数。当我从 localhost 或 Postman 调用它们时,我的 Firebase 函数就会执行。但是当我从我的域 (moonio.io) 调用函数时,它们没有被执行,唯一发生的事情是我取回了我的 index.js 文件。因此,我怀疑我的问题是由 firebase.json 文件的托管部分的重写引起的(api 地址“https://europe-west3-cryptocurrency-tracker-moonio.cloudfunctions.net/api”被重写到“/index.html”)?

firebase.json

{
  "hosting": [
    {
      "target": "app",
      "public": "app/build",
      "rewrites": [
        {
          "source": "**",
          "destination": "/index.html"
        }
      ]
    }
  ],
  "functions": {
    "source": "functions"
  }
}

用于 Firebase 函数的 package.json

{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "scripts": {
    "lint": "eslint .",
    "serve": "firebase emulators:start --only functions",
    "shell": "firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "engines": {
    "node": "12"
  },
  "main": "index.js",
  "dependencies": {
    "axios": "^0.21.1",
    "express": "^4.17.1",
    "firebase": "^8.1.1",
    "firebase-admin": "^9.2.0",
    "firebase-functions": "^3.13.1",
    "google-auth-library": "^6.1.3",
    "react-redux": "^7.2.2",
    "redux": "^4.0.5",
    "redux-thunk": "^2.3.0"
  },
  "devDependencies": {
    "eslint": "^5.12.0",
    "eslint-plugin-promise": "^4.0.1",
    "firebase-functions-test": "^0.2.0"
  },
  "private": true
}

我的 React 应用程序的 package.json

{
  "name": "cryptotracker",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@fortawesome/fontawesome-svg-core": "^1.2.32",
    "@fortawesome/free-solid-svg-icons": "^5.15.1",
    "@fortawesome/react-fontawesome": "^0.1.13",
    "@material-ui/core": "^4.11.0",
    "@material-ui/icons": "^4.9.1",
    "@material-ui/lab": "^4.0.0-alpha.57",
    "axios": "^0.20.0",
    "chart.js": "^2.9.4",
    "chartjs": "^0.3.24",
    "colorthief": "^2.3.2",
    "cra-template": "1.0.3",
    "firebase": "^8.2.3",
    "history": "^5.0.0",
    "install": "^0.13.0",
    "jwt-decode": "^3.1.2",
    "lodash": "^4.17.20",
    "npm": "^6.14.10",
    "prop-types": "^15.7.2",
    "react": "^16.13.1",
    "react-chartjs-2": "^2.11.1",
    "react-dom": "^16.13.1",
    "react-google-login": "^5.2.2",
    "react-hook-form": "^6.9.1",
    "react-loading-skeleton": "^2.1.1",
    "react-redux": "^7.2.2",
    "react-router-dom": "^5.2.0",
    "react-scripts": "3.4.3",
    "react-virtualized-select": "^3.1.3",
    "redux": "^4.0.5",
    "redux-thunk": "^2.3.0",
    "retry-axios": "^2.3.0",
    "styled-components": "^5.2.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "proxy": "https://europe-west3-cryptocurrency-tracker-moonio.cloudfunctions.net/api"
}

标签: reactjsgoogle-cloud-functionsfirebase-hosting

解决方案


几个小时后,我终于发现了问题。

  1. 需要向 firebase.json 文件添加另一个重写以处理 api。所有对 api 的请求都必须到 Firebase 函数中对应的 api 函数,其他所有请求都到 index.html,根据单页应用的要求。因此,firebase.json 的重写部分需要如下所示:
"rewrites": [
        {
          "source": "/api/**",
          "function": "api"
        },
        {
          "source": "!/api/**",
          "destination": "/index.html"
        }
      ]
  1. package.json 文件中的代理仅用于开发目的。它在生产中不起作用。只要您设置了自定义域,Firebase 就会自动将此域链接到您的函数。因此,由于我的自定义域是 moonio.io,因此可以通过向 moonio.io/api/<FUNCTION_NAME> 发送请求来执行 Firebase 功能。为了使对这些端点的请求正常工作,您还必须在 node.js 中的函数设置中的请求 url 中包含“/api”。我正在使用 express,所以我的 index.js 文件的示例函数如下所示(注意“/api”是 url 的一部分):
const app = require("express")();
const functions = require("firebase-functions");

app.post("/api/signin", signIn);

exports.api = functions.region("us-central1").https.onRequest(app);
  1. 此外,在从前端向 Firebase 函数发出请求时,必须在 url 的开头包含“/api”,正如我在以下示例函数中所做的那样:
axios.post("/api/signin", userData)
  1. Firebase 函数仅适用于 us-central1 中的 Firebase 托管。如果您使用的是其他位置,请根据我在第 2 部分中的代码示例进行更改。

推荐阅读