当使用 headers 发送 POST 请求时,Firebase HTTP 函数触发两次

Firebase HTTP Function triggered twice when POST request sent with headers

我部署了 firebase HTTP cloud function 并且遇到了这种(意外)行为:

这是我不理解的正常行为还是潜在的错误?

我的最小云函数

exports.run = functions.https.onRequest(async (req, res) => {
  // ALLOW CORS FOR POST REQUEST:
  // => 
  res.set('Access-Control-Allow-Origin', '*');
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");

  return res.status(200).send({
    status: "ok",
    body: req.body,
    query: req.query,
  }).end();
});

从前端调用

// example data (not a real one)
const url = "https://us-central1-myproject.cloudfunctions.net/test";
const postData = { x: 1, y: 2 };

// GET request => ✅ works as expected
fetch(url);

// POST request without headers => ✅ works as expected
fetch(url, {
  method: 'POST',
  body: JSON.stringify(postData),
});

// POST request with headers => ❌ 2 requests get triggered
fetch(url,  {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(postData),
});

此行为的发生是因为 CORS preflight request:

A CORS preflight request is a CORS request that checks to see if the CORS protocol is understood and a server is aware using specific methods and headers. ... A preflight request is automatically issued by a browser, and in normal cases, front-end developers don't need to craft such requests themselves. It appears when a request is qualified as "to be preflighted" and omitted for simple requests.

正如另一个 question 中所指出的:

As long as you’re adding a Content-Type': 'application/json' header to the request, the browser is going to automatically on its own do a CORS preflight OPTIONS request before trying the request from your code.

因此,这是正常行为,不是 Cloud Functions for Firebase 的问题。

为了没有这两个请求,您可以按照此 answer:

的建议更改 header 请求
// example data (not a real one)
const url = "https://us-central1-myproject.cloudfunctions.net/test";
const postData = { x: 1, y: 2 };
    
// POST request with different header  => ✅ only one request is triggered
fetch(url, {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: JSON.stringify(postData),
}).then(data => console.log(data));