簡體   English   中英

Firebase 雲功能上的預檢錯誤

[英]Preflight error on Firebase cloud functions

當我嘗試從我的網站調用我的雲 function 時,我遇到了預檢錯誤。 我在我的雲 function 中實現了 cors 模塊,我的請求得到了 cors Z099FB995346F31C75E3F6 授權

雲function:

const cors = require('cors')({ origin: true });
exports.CLOUDFUNCTION = functions.https.onRequest(
  (request: any, response: any) => {
    cors(request, response, async () => {
      response.status(200).send('hello');
    })
  }
);

網站要求:

fetch('FIREBASE_URL/CLOUDFUNCTION',
          {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
              'Access-Control-Allow-Origin': '*',
              'Access-Control-Allow-Headers': 'Content-Type',
              'Access-Control-Allow-Headers': 'Authorization'
               
            },
            body: JSON.stringify(body), // body is a simple {"variable": "value"}
          }
        );

錯誤

Access to fetch at 'FIREBASE_URL/CLOUDFUNCTION' from origin 'MYWEBSITE' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

如果您在嘗試通過 URL 訪問您的 function 時遇到 403 禁止錯誤,則您的函數部署有問題,它的配置有問題,或者您在 ZE485903D2A8D2C5DZ 中出錯了

注意:雖然我在此處使用“傳統” require語句來匹配您的示例,但我鼓勵您對任何新編寫的函數使用更新的 ES6+ JavaScript 功能( constletasync / awaitimport等)。

使用最新的firebase-tools版本進行部署

確保您使用最新版本的firebase-tools CLI 進行部署。

v7.7.0 firebase-tools v7.7.0 發布(2020 年 1 月 15 日)時,在服務器上調用 Cloud Functions 的方式發生了變化,因此只能由經過身份驗證的用戶調用函數。 為了讓 Firebase 用戶可以訪問,必須通過顯式授予allUsersCloud Function Invoker權限來公開這些功能。

v7.7.0及更高版本中,這是作為部署的一部分為您完成的。 但是,如果您使用舊版本部署功能,則需要自己配置此權限或使用更新的firebase-tools版本重新部署。

檢查導出的 function 名稱

確保您導出的 function 在部署后命名為您期望的名稱。

特別是,當您的 function 被有意或無意地作為function 組的一部分導出時,請密切注意。 當您將函數拆分為多個文件時,通常會出現這種情況。 在下面的代碼塊中, CLOUDFUNCTION被導出為myFunctions-CLOUDFUNCTION而不僅僅是CLOUDFUNCTION如您所料。

// myFunctions.js
exports.CLOUDFUNCTION = functions.https.onRequest(...);
// index.js (incorrect)
exports.myFunctions = require("./myFunctions.js");
// index.js (correct)
const myFunctions = require("./myFunctions.js");

exports.CLOUDFUNCTION = myFunctions.CLOUDFUNCTION;

檢查函數的 URL

檢查您使用的 Cloud Functions URL 是否存在拼寫錯誤。 Cloud Functions URL 中的 Function 名稱區分大小寫。

正確的 URL 應遵循以下格式:

https://<REGION>-<PROJECT_ID>.cloudfunctions.net/<EXPORTED_FUNCTION_NAME>

例子:

https://us-central1-fir-sandbox.cloudfunctions.net/echo

處理 CORS 錯誤並停止處理

在您的代碼示例中,您傳入NextFunction而沒有錯誤處理程序。 使用{ origin: true }時,這“很好”,但是當您開始限制您調用 function 的來源時,您將開始遇到麻煩。 這對於防止您的函數被它們的 URL (其中origin將是undefined )直接調用特別方便。 查看文檔或下一部分以獲取更多信息。

const cors = require('cors')({ origin: true });
exports.CLOUDFUNCTION = functions.https.onRequest(
  (request, response) => { // <-- don't use `: any` here, as you are disabling the built-in types provided by firebase-functions
    cors(request, response, async (err) => {
      if (err) {
        // Denied by CORS/error with CORS configuration
        console.error("CORS blocked request -> ", err);
        response.status(403).send("Forbidden by CORS");
        return;
      }

      response.status(200).send('hello');
    })
  }
);

可選:擰緊cors配置

雖然您可以使用cors package 反映Access-Control-*標頭,但請考慮明確設置這些服務器端。

const { projectId: PROJECT_ID } = JSON.parse(process.env.FIREBASE_CONFIG);

const cors = require('cors')({
  // during emulation, allow localhost & calling directly (i.e. no origin specified);
  // at all other times, restrict to deployed hosting sites only
  origin: process.env.FUNCTIONS_EMULATOR === "true"
    ? /^(https?:\/\/localhost:\d+|undefined)$/
    : [`https://${PROJECT_ID}.firebaseapp.com`, `https://${PROJECT_ID}.web.app`],
  allowedHeaders: ['Content-Type', 'Authorization']
});

exports.CLOUDFUNCTION = functions.https.onRequest(
  (request, response) => {
    cors(request, response, async (err) => {
      if (err) {
        // Denied by CORS/error with CORS configuration
        console.error("CORS blocked request -> ", err);
        response.status(403).send("Forbidden by CORS");
        return;
      }

      response.status(200).send('hello');
    })
  }
);

這簡化了您的客戶端代碼:

fetch('FIREBASE_URL/CLOUDFUNCTION',
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  }
);

可選:使用可調用函數

如果您的函數需要您代表用戶執行操作,您可以使用Callable Cloud Functions而不是更簡單的 HTTPS 請求函數。 這個版本的 HTTPS Function 處理 CORS,身份驗證,並支持基於 Promise 的數據返回。

注意:這仍然需要 function 如上所述公開。

在服務器端:

exports.CLOUDFUNCTION = functions.https.onCall(async (data, context) => {
  if (!context.auth) {
    // users must be logged in
    throw new functions.https.HttpsError(
      'failed-precondition',
      'The function must be called while authenticated.'
    );
  }

  if (data.variable === undefined)) {
    throw new functions.https.HttpsError(
      'invalid-argument',
      'Parameter "variable" must be a string'
    );
  }

  // you can return a promise here
  // this sends back the JSON string "hello world"
  return "hello world";
});

在客戶端:

const callFunction = firebase.functions().httpsCallable('CLOUDFUNCTION');

callFunction(body)
  .then(
    (responseData) => {
      // TODO: handle response
    },
    (functionError) => {
      // TODO: handle error
    }
  );

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM