Cloud Functions Cors 错误“对预检请求的响应未通过访问控制检查”

Posted

技术标签:

【中文标题】Cloud Functions Cors 错误“对预检请求的响应未通过访问控制检查”【英文标题】:Cloud Functions Cors error "Response to preflight request doesn't pass access control check" 【发布时间】:2018-07-28 04:02:15 【问题描述】:

我有一个简单的 firebase 设置和一个离子应用程序。几天来,我一直在尝试让云功能正常工作。但是这个错误似乎并没有消失:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://us-central1-my-app.cloudfunctions.net/savedProfiles. (Reason: CORS preflight channel did not succeed).

从前端我有这个:

let token = this.auth.user.getIdToken();

    const httpOptions = 
      headers: new HttpHeaders(
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'POST, GET, OPTIONS, PUT',
        'Accept':'application/json',
        'Content-Type': 'application/json',
        'Authorization': `Bearer $token` )
      ;

    this.httpClient.get('https://us-central1-my-app.cloudfunctions.net/savedProfiles', httpOptions)
    .subscribe(data => 
      console.log(data);
  );

我的云函数如下所示:

'use strict';

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const express = require('express');
const cookieParser = require('cookie-parser')();
const cors = require('cors')(
  origin: true,
  allowedHeaders: ['Content-Type', 'Authorization', 'Content-Length', 'X-Requested-With', 'Accept'],
  methods: ['OPTIONS', 'GET', 'PUT', 'POST', 'DELETE']
);
const app = express();

// Express middleware that validates Firebase ID Tokens passed in the Authorization HTTP header.
// The Firebase ID token needs to be passed as a Bearer token in the Authorization HTTP header like this:
// `Authorization: Bearer <Firebase ID Token>`.
// when decoded successfully, the ID Token content will be added as `req.user`.
const validateFirebaseIdToken = (req, res, next) => 

  console.log('Check if request is authorized with Firebase ID token');


  if ((!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) &&
      !req.cookies.__session) 
    console.error('No Firebase ID token was passed as a Bearer token in the Authorization header.',
        'Make sure you authorize your request by providing the following HTTP header:',
        'Authorization: Bearer <Firebase ID Token>',
        'or by passing a "__session" cookie.');

    res.set('Access-Control-Allow-Origin', '*')
       .set('Access-Control-Allow-Methods', 'OPTIONS, POST, GET, PUT')
       .status(403).send('Unauthorized');
    return;
  

  let idToken;
  if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) 
    console.log('Found "Authorization" header');
    // Read the ID Token from the Authorization header.
    idToken = req.headers.authorization.split('Bearer ')[1];
   else 
    console.log('Found "__session" cookie');
    // Read the ID Token from cookie.
    idToken = req.cookies.__session;
  

  admin.auth().verifyIdToken(idToken).then((decodedIdToken) => 
    console.log('ID Token correctly decoded', decodedIdToken);
    req.user = decodedIdToken;
    return next();
  ).catch((error) => 
    console.error('Error while verifying Firebase ID token:', error);
    res.set('Access-Control-Allow-Origin', '*')
       .set('Access-Control-Allow-Methods', 'OPTIONS, POST, GET, PUT')
       .status(403)
       .send('Unauthorized');
  );
;


app.use(cors);
app.use(cookieParser);
app.use(validateFirebaseIdToken);
app.get('/savedProfiles', (req, res) => 
  res.set('Access-Control-Allow-Origin', '*')
     .set('Access-Control-Allow-Methods', 'OPTIONS, POST, GET, PUT')
     .send(`Hello $req.user.name`);
);

// This HTTPS endpoint can only be accessed by your Firebase Users.
// Requests need to be authorized by providing an `Authorization` HTTP header
// with value `Bearer <Firebase ID Token>`.
exports.savedProfiles = functions.https.onRequest(app);

这类似于此处的示例代码:https://github.com/firebase/functions-samples/tree/master/authorized-https-endpoint

我确信解决方案很简单,但我似乎无法理解发生了什么。我以为app.use(cors); 应该解决这些问题?如果我不添加res.set('Access-Control-Allow-Origin', '*'),那么我会得到一个

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://us-central1-my-app.cloudfunctions.net/savedProfiles. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).

错误。从控制台日志返回到我的控制台的错误是这样的:

error: error  target: XMLHttpRequest, isTrusted: true, lengthComputable: false, … 
headers: Object  normalizedNames: Map, lazyUpdate: null, headers: Map 
message: "Http failure response for (unknown url): 0 Unknown Error"
name: "HttpErrorResponse"
ok: false
status: 0
statusText: "Unknown Error"
url: null

如果您希望我扩展错误,请告诉我。谢谢

【问题讨论】:

按照此处的说明使用 onCall 检查 ***.com/questions/51066434/… 【参考方案1】:

您需要在初始化函数和express 函数之前添加cors

'use strict';

import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'
import * as cors from 'cors';
import * as express from 'express';

cors(
  origin: true,
); // << for bootstrap 
admin.initializeApp(functions.config().firebase);

const app = express();
app.use(cors()); // << for what you just defined

这应该可以正常工作

【讨论】:

以上是关于Cloud Functions Cors 错误“对预检请求的响应未通过访问控制检查”的主要内容,如果未能解决你的问题,请参考以下文章

Google Cloud Functions 启用 CORS?

Cloud Functions for Firebase 在 CORS 预检请求上触发功能

无法在安全的Google Cloud Function上获得CORS错误

Cloud Functions 返回 403 错误也具有 Cloud Functions Invoker 权限

如何处理 Firebase Cloud Functions 中的错误 JSON?

为啥我在 Firebase Cloud Functions 中收到“无效信封”错误? [关闭]