【问题标题】:My Web app is being blocked by CORS policy even after installing CORS in my Express app即使在我的 Express 应用程序中安装了 CORS,我的 Web 应用程序仍被 CORS 策略阻止
【发布时间】:2021-09-29 23:37:40
【问题描述】:

我有一个在 localhost 上运行的 Flutter Web 应用程序进行调试,我的 Web 应用程序将数据发布到我的 Firebase Cloud 函数 API,然后将数据发送到 Google Bigquery 以创建一个表,尽管我已经安装了 CORS 我不断得到下面我的浏览器中出现此错误

Access to XMLHttpRequest at 'https://us-central1-denance-cbf3f.cloudfunctions.net/api/create_table' from origin 'http://localhost:55073' 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.
    us-central1-denance-cbf3f.cloudfunctions.net/api/create_table:1 Failed to load resource: net::ERR_FAILED
    errors.dart:202 Uncaught (in promise) Error: XMLHttpRequest error.
        C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart 897:28                get current
    packages/http/src/browser_client.dart 71:22                                                                                    <fn>
    C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/zone.dart 1687:54                                              runUnary
    C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 155:18                                        handleValue
    C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 707:44                                        handleValueCallback
    C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 736:13                                        _propagateToListeners
    C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 533:7                                         [_complete]
    C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/stream_pipe.dart 61:11                                         _cancelAndValue
    C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/stream.dart 1219:7                                             <fn>
    C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 324:14  _checkAndCall
    C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 329:39  dcall
    C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/html/dart2js/html_dart2js.dart 37324:58                              <fn>
    
    
        at Object.createErrorWithStack (:55073/dart_sdk.js:5070)
        at Object._rethrow (:55073/dart_sdk.js:37715)
        at async._AsyncCallbackEntry.new.callback (:55073/dart_sdk.js:37711)
        at Object._microtaskLoop (:55073/dart_sdk.js:37568)
        at _startMicrotaskLoop (:55073/dart_sdk.js:37574)
        at :55073/dart_sdk.js:33324

这是我下面的代码

const functions = require("firebase-functions");

const express = require('express');
var cors = require('cors');
const { BigQuery } = require('@google-cloud/bigquery');

const bigquery = new BigQuery();
var app = express();
app.use(cors);
app.use(express.json());

exports.api = functions.https.onRequest(app);


app.post('/create_table', cors(dynamicCorsOptions), function (req, res,) {


  'use strict';


  async function createTable() {


    let schema = [];


    async function groupUp() {

      for (let key in req.body) {


        schema.push({ name: req.body[key]['name'], type: req.body[key]['type'] });


      }


    }

    await groupUp();


    await doingIt();


    async function doingIt() {


      var datasetId = 'denanse'; // Existing dataset
      var tableId = 'hrhrhhh'; // Table to be created

      const options = {
        schema: schema,
        location: 'US',
      };

      const [table] = await bigquery
        .dataset(datasetId)
        .createTable(tableId, options);

      console.log(`Table ${table.id} created.`);
      res.send(`Table ${table.id} created.`);

    }

  }

  createTable();


});

我该如何解决这个问题?

【问题讨论】:

标签: google-bigquery google-cloud-functions cors


【解决方案1】:

目前,您对cors 包的使用存在两个方面的问题。您只需要实施以下任一修复即可。

在所有路由上启用 CORS

因为您已经像这样导入并使用了cors 包:

var cors = require('cors');
// ...
app.use(cors);

您已将 cors 构造函数附加到 Express 应用程序,而不是 cors 中间件的实例(您使用 cors(request) 调用 cors(options))。 documentation 中介绍了选项对象及其属性。

在其最基本的形式中,您可以不使用任何配置来允许对所有请求进行 CORS:

app.use(cors())

但是,这实际上与手动将 CORS 标头设置为 * 以及 some other headers 相同。

这是不安全的,并且违背了 CORS 的观点。您应该改为配置它,以便只接受与您的项目相关的少数来源。

/** The current project's ID */
export const PROJECT_ID = JSON.parse(process.env.FIREBASE_CONFIG).projectId;

/** Array of permitted origins for CORS */
export const CORS_ALLOWED_ORIGINS = [
  "https://my.custom.domain",                // 0+ custom domains related to your project
  `https://${PROJECT_ID}.firebaseapp.com`,   // legacy Firebase Hosting domain
  `https://${PROJECT_ID}.web.app`,           // modern Firebase Hosting domain
  ...(process.env.NODE_ENV === "production"
    ? []
    : ["localhost", "undefined"]             // permit CORS on localhost, only while emulated
  ),
];

app.use(cors({ origin: CORS_ALLOWED_ORIGINS }))

仅在 /create_table 上启用 CORS

与上述类似,您已使用以下方法将 cors() 中间件附加到 /create_table 路由:

app.post('/create_table', cors(dynamicCorsOptions), function (req, res) { /* ... */ });

这里,dynamicCorsOptionsundefined(至少在您共享的代码中),它将在对 POST /create_table 的请求中使用 CORS 中间件。但是,您也需要处理OPTIONS /create_table

// handle preflight requests
app.options('/create_table', cors(dynamicCorsOptions));

// handle actual requests
app.post('/create_table', cors(dynamicCorsOptions), function (req, res) { /* ... */ });

您甚至可以使用上述部分中的cors({ origin: CORS_ALLOWED_ORIGINS })

其他积分

  • Functions Framework(运行您的函数),如documented here,会为您解析请求的主体(如果设置了适当的标头)。这意味着您不需要app.use(express.json())
  • 您的代码调用createTable(),但如果失败则不处理,这将引发未处理的 Promise 异常并终止您的函数。您可以使用 catch() 或下一个 sn-p 中的 try/catch 块来处理这种情况:
createTable()
  .catch((err) => {
    console.error("Failed to create table: " + err.code || err.message, err);
    res.status(500)
      .send("Failed to create table with unknown error");
  });
  • 目前,/create_table 处理程序的执行会跳动很多,我建议重新安排它以提高可读性:
app.post('/create_table', cors(dynamicCorsOptions), function (req, res) {
  'use strict';

  // this could be moved outside of the handler
  async function groupUp(requestBody) {
    const groups = [];
 
    for (let key in requestBody) {
      const { name, type } = requestBody[key];
      groups.push({ name, type });
    }

    return groups;
  }

  // this could be moved outside of the handler
  async function createTableInDataset(datasetId, schema) {
    const tableId = /* generate table ID */;

    const [table] = await bigquery
      .dataset(datasetId)
      .createTable(tableId, {
        schema,
        location: 'US',
      });

    return table.id;
  }

  async function createTable() {
    try {
      const schema = await groupUp(req.body);

      const createdTableId = createTableInDataset('denanse', schema);

      console.log(`Table ${createdTableId} created.`);
      res.status(201)
        .send(`Table ${createdTableId} created.`);
    } catch (err) {
      console.error("Failed to create table: " + err.code || err.message, err);
      res.status(500)
        .send("Failed to create table with unknown error");
    }
  }

  createTable();
});

【讨论】:

  • @JimG。对每个问题/答案发送垃圾评论是没有帮助的。为此,请使用“关闭-> 标记为重复”。虽然您的链接问题适用于一般 GCF 功能(直到我编辑 accepted answer 有一个重大错误),CGF 的 Firebase 分支允许对 CORS 行为进行更精细的控制,如此处所述。理解问题比仅仅指出答案要好。
猜你喜欢
  • 2017-07-05
  • 2019-08-26
  • 2020-10-16
  • 2020-02-15
  • 2020-08-15
  • 2023-03-05
  • 2021-04-24
  • 2022-01-06
  • 1970-01-01
相关资源
最近更新 更多