Kích hoạt CORS trong các chức năng đám mây cho Firebase


141

Tôi hiện đang tìm hiểu cách sử dụng các Hàm đám mây mới cho Firebase và vấn đề tôi gặp phải là tôi không thể truy cập vào chức năng mà tôi đã viết thông qua yêu cầu AJAX. Tôi gặp lỗi "Không 'Kiểm soát truy cập-Cho phép-Xuất xứ'". Đây là một ví dụ về chức năng tôi đã viết:

exports.test = functions.https.onRequest((request, response) => {
  response.status(500).send({test: 'Testing functions'});
})

Hàm nằm trong url này: https://us-central1-fba-shipper-140ae.cloudfifts.net/test

Tài liệu Firebase đề xuất thêm phần mềm trung gian CORS bên trong chức năng, tôi đã thử nó nhưng nó không hoạt động với tôi: https://firebase.google.com/docs/fifts/http-events

Đây là cách tôi đã làm nó:

var cors = require('cors');    

exports.test = functions.https.onRequest((request, response) => {
   cors(request, response, () => {
     response.status(500).send({test: 'Testing functions'});
   })
})

Tôi đang làm gì sai? Tôi sẽ đánh giá cao bất kỳ sự giúp đỡ với điều này.

CẬP NHẬT:

Câu trả lời của Doug Stevenson đã giúp. Việc thêm ({origin: true}) đã khắc phục sự cố, tôi cũng phải thay đổi response.status(500)thành lỗi response.status(200)mà tôi đã hoàn toàn bỏ qua lúc đầu.


Cũng là một mẫu trong các tài liệu ở đây
Kato

Tôi có một số chức năng hoạt động với giải pháp được cung cấp nhưng hiện đang thử một chức năng mới, về cơ bản sẽ thêm các biểu đồ mở vào đầu index.html của tôi và trả về index.html được cập nhật và tôi không thể làm cho nó hoạt động :( tiếp tục nhận lỗi TRUY CẬP-KIỂM SOÁT ---
TheeBen

2
gói yêu cầu đến trong cors () như trên là điều duy nhất hiệu quả với tôi
Charles Harring

bạn có thể chỉnh sửa "cập nhật" của mình để gạch chân rằng phần mềm trung gian cors là bắt buộc không? Điều này sẽ giúp một số người tiết kiệm thời gian
Antoine Weber

Câu trả lời:


151

Có hai chức năng mẫu được cung cấp bởi nhóm Firebase thể hiện việc sử dụng CORS:

Mẫu thứ hai sử dụng một cách làm việc khác với cors so với hiện tại bạn đang sử dụng.

Ngoài ra, hãy xem xét nhập như thế này, như thể hiện trong các mẫu:

const cors = require('cors')({origin: true});

2
Cảm ơn bạn! Thêm ({origin: true}) đã giúp.
Andrey Pokrovskiy

2
Thật tuyệt, bạn chắc chắn cần phải origin: truebỏ nó đi sẽ khiến nó không hoạt động
Scott

4
Có vẻ như đây là nơi danh sách trắng của các tên miền để cho phép truy cập được xác định? Và thiết lập origin: truecho phép bất kỳ tên miền để truy cập? ( npmjs.com/package/cors ) @Doug Stevenson Bạn có nghĩ firebase có thể viết một tài liệu về những điều cơ bản cần thiết cho các chức năng https của máy khách / máy chủ không? Các mẫu repo là tốt, nhưng chúng tôi đã bỏ lỡ thêm một chút yêu cầu.
Alan

9
Đối với bất kỳ ai sẵn sàng thêm hỗ trợ CORS vào back-end của họ: vui lòng đảm bảo bạn hiểu hậu quả và cách định cấu hình đúng. "origin: true" rất tuyệt để thử nghiệm nhưng nó đánh bại toàn bộ mục đích :)
dSebastien

1
Các chức năng của đám mây google không cho phép nguồn gốc ký tự đại diện: cloud.google.com/fifts/docs/wr/ cấp
Corey Cole

73

Bạn có thể đặt CORS trong chức năng đám mây như thế này

response.set('Access-Control-Allow-Origin', '*');

Không cần nhập corsgói


2
Điều này hoạt động hoàn hảo cho trường hợp của tôi, một chức năng đám mây thực hiện cuộc gọi XHR đến API Mailchimp.
elverde

1
Đó là câu trả lời cần thiết.
Jimmy Kane

1
Các chức năng của đám mây google không cho phép nguồn gốc ký tự đại diện: cloud.google.com/fifts/docs/wr/ cấp
Corey Cole

4
@CoreyCole Tôi nghĩ rằng chỉ khi bạn cần thêm Authorizationtiêu đề. Ở trên có vẻ hoạt động tốt.
Ghi nhớ Stuart

Nơi để đặt dòng mã này? Phần nào của hàm đám mây?
Antonio Ooi

41

Đối với bất kỳ ai đang cố gắng thực hiện điều này trong Bản mô tả thì đây là mã:

import * as cors from 'cors';
const corsHandler = cors({origin: true});

export const exampleFunction= functions.https.onRequest(async (request, response) => {
       corsHandler(request, response, () => {});
       //Your code here
});

3
Giải pháp sẽ khiến bạn mất đăng nhập vào các chức năng đám mây (rất tệ) và chức năng async / await thích hợp, bạn có nguy cơ nội dung chức năng bị kết thúc sớm bên trong cuộc gọi lại trong các cuộc gọi dài.
Oliver Dixon

2
Các chức năng của đám mây google không cho phép nguồn gốc ký tự đại diện: cloud.google.com/fifts/docs/wr/ cấp
Corey Cole

29

Một thông tin bổ sung, chỉ vì lợi ích của những người này sau một thời gian: Nếu bạn đang sử dụng lưu trữ firebase, bạn cũng có thể thiết lập viết lại, ví dụ như một url như (firebase_hosting_host) / api / myfeft chuyển hướng đến ( hàm firebase_cloudfifts_host) / doStuff. Theo cách đó, vì chuyển hướng là trong suốt và phía máy chủ, bạn không phải đối phó với cors.

Bạn có thể thiết lập phần đó với phần viết lại trong firebase.json:

"rewrites": [
        { "source": "/api/myFunction", "function": "doStuff" }
]

1
imo, đây là câu trả lời tốt nhất, vì nó giải quyết vấn đề thực tế mà không cần thêm bất kỳ vấn đề bảo mật nào. Bằng cách này, các hàm đám mây được phục vụ từ cùng một miền với phần còn lại và bạn thậm chí không cần bất kỳ phần tử nào.
koljaTM

3
Đây thực sự là một tính năng tuyệt vời, nhưng hiện tại nó chỉ hoạt động nếu các chức năng nằm trong vùng mặc định (us-centre1). Tôi muốn triển khai các chức năng của mình đến europe-west1 vì lý do độ trễ và gặp phải vấn đề này: github.com/firebase/firebase-tools/issues/842
Alex Suzuki

Chuyển hướng hoạt động tốt và làm cho URL sạch hơn, nhưng tôi chưa tìm ra cách truyền tham số GET. Hàm (sau khi viết lại) dường như được gọi mà không có tham số.
royappa

20

Không có giải pháp CORS nào làm việc cho tôi ... cho đến bây giờ!

Không chắc có ai khác gặp phải vấn đề tương tự tôi đã làm hay không, nhưng tôi đã thiết lập CORS như 5 cách khác nhau từ các ví dụ tôi tìm thấy và dường như không có gì hoạt động. Tôi đã thiết lập một ví dụ tối thiểu với Plunker để xem nó có thực sự là một lỗi không, nhưng ví dụ này chạy rất đẹp. Tôi quyết định kiểm tra nhật ký các chức năng của căn cứ hỏa lực (được tìm thấy trong bảng điều khiển căn cứ hỏa lực) để xem điều đó có thể cho tôi biết bất cứ điều gì không. Tôi đã có một vài lỗi trong mã máy chủ nút , không liên quan đến CORS , khi tôi gỡ lỗi đã giải phóng cho tôi thông báo lỗi CORS của tôi . Tôi không biết tại sao các lỗi mã không liên quan đến CORS trả về phản hồi lỗi CORS, nhưng nó đã dẫn tôi xuống lỗ thỏ sai trong một số giờ tốt ...

tl; dr - kiểm tra nhật ký chức năng căn cứ hỏa lực của bạn nếu không có giải pháp CORS nào hoạt động và gỡ lỗi bất kỳ lỗi nào bạn có


1
Điều này làm tôi phát điên. trong trường hợp của tôi, nó thậm chí không có lỗi trong mã! nó đã được Error: quota exceeded (Quota exceeded for quota group 'NetworkIngressNonbillable' and limit 'CLIENT_PROJECT-1d' of service 'cloudfunctions.googleapis.com hạn ngạch nên về cơ bản miễn phí đã vượt quá chức năng và trở CORS lỗi
Stanislau Buzunko

Xảy ra một vài lần ở đây, lỗi tương tự được trả về từ máy chủ cũng như cors: Error: Internal về cơ bản là lỗi. Lỗi này cũng sẽ xảy ra nếu bạn chạy sai chức năng, ví dụ như nhập sai tên hàm
Henrik Bøgelund Lavstsen

Khi bạn cố gắng yêu cầu xác minh Google reCAPTCHA trong chức năng đám mây, trình duyệt cũng sẽ đưa ra lỗi CORS. Khi tôi kiểm tra nhật ký chức năng Firebase Console, nó báo access to external network resources not allowed if the billing account is not enabled. Sau khi kích hoạt tài khoản thanh toán, nó hoạt động hoàn hảo. Đây cũng là một trong những ví dụ không liên quan đến cors nhưng lỗi cors bị ném.
Antonio Ooi

19

Tôi có một chút bổ sung cho câu trả lời @Andreys cho câu hỏi của chính mình.

Có vẻ như bạn không phải gọi lại cors(req, res, cb)hàm trong hàm, vì vậy bạn chỉ có thể gọi mô-đun cors ở đầu hàm, mà không nhúng tất cả mã của bạn vào hàm gọi lại. Điều này nhanh hơn nhiều nếu bạn muốn thực hiện cors sau đó.

exports.exampleFunction = functions.https.onRequest((request, response) => {
    cors(request, response, () => {});
    return response.send("Hello from Firebase!");
});

Đừng quên init cors như đã đề cập trong bài mở đầu:

const cors = require('cors')({origin: true});


1
điều này hoạt động khi các câu trả lời SO khác với việc đặt tiêu đề bằng tay không
Jim Factor

Điều này hoạt động nhưng nó có thể gây ra lỗi TSlint nếu bạn đã bật và bạn không thể triển khai đến căn cứ hỏa lực. Đặt câu trả lời bên trong đóng cửa để khắc phục nócors(request, response, () => { return response.send("Hello from Firebase!"); });
Xoắn ốc ra

1
2 lỗi đây các bạn ạ. Đầu tiên. Bất cứ điều gì sau chức năng cors sẽ chạy hai lần (vì yêu cầu đầu tiên là preflight). Không tốt. Thứ hai, @SpirusOut giải pháp của bạn sẽ khiến bạn mất đăng nhập vào các chức năng đám mây (rất tệ) và chức năng async / await thích hợp, bạn có nguy cơ nội dung chức năng bị kết thúc sớm trong cuộc gọi lại.
Oliver Dixon

@SpirusOut bạn chỉ có thể vô hiệu hóa tslint
Vlad

1
Đã học được rất nhiều về gcf trong năm ngoái, tôi sẽ không đề xuất câu trả lời này nữa. Nó có thể hữu ích cho các nguyên mẫu nhanh, nhưng tránh điều này trong các trường hợp sản xuất thực tế
Jaap Weijland 17/03/19

11

Điều này có thể hữu ích. Tôi đã tạo chức năng đám mây HTTP firebase với express (URL tùy chỉnh)

const express = require('express');
const bodyParser = require('body-parser');
const cors = require("cors");
const app = express();
const main = express();

app.post('/endpoint', (req, res) => {
    // code here
})

app.use(cors({ origin: true }));
main.use(cors({ origin: true }));
main.use('/api/v1', app);
main.use(bodyParser.json());
main.use(bodyParser.urlencoded({ extended: false }));

module.exports.functionName = functions.https.onRequest(main);

Hãy chắc chắn rằng bạn đã thêm phần viết lại

"rewrites": [
      {
        "source": "/api/v1/**",
        "function": "functionName"
      }
]

1
Câu trả lời của bạn quá thấp bạn ạ, câu trả lời tốt nhất cho đến nay.
Avram Virgil

Cảm ơn. @AvramVirgil
Sandy

Đây là cách nhanh nhất và dễ nhất trong tất cả, Cảm ơn!
Gaurav Kakkar

8

Tôi vừa xuất bản một mẩu nhỏ về điều đó:

https://mhaligowski.github.io/blog/2017/03/10/cors-in-cloud-fifts.html

Nói chung, bạn nên sử dụng gói Express CORS , yêu cầu một chút hack xung quanh để đáp ứng các yêu cầu trong Hàm GCF / Firebase.

Mong rằng sẽ giúp!


4
Không chắc chắn những gì bạn có nghĩa là hack? Muốn trau chuốt một chút? Đọc bài đăng của bạn nhưng tôi không thấy bạn đề cập đến nó
TheeBen

1
tác giả của mô-đun cors ở đây; bằng cách "hack" mhaligowski đơn giản có nghĩa là anh ta phải thực hiện cuộc gọi đến mô-đun cors để làm cho nó khớp với cách Express gọi phần mềm trung gian (tức là cung cấp một hàm làm tham số thứ ba sau req & res)
Troy

4

Nếu có những người như tôi ngoài kia: Nếu bạn muốn gọi hàm đám mây từ cùng một dự án với chức năng đám mây tự nó, bạn có thể khởi tạo sdk firebase và sử dụng phương thức onCall. Nó sẽ xử lý mọi thứ cho bạn:

exports.newRequest = functions.https.onCall((data, context) => {
    console.log(`This is the received data: ${data}.`);
    return data;
})

Gọi hàm này như thế này:

// Init the firebase SDK first    
const functions = firebase.functions();
const addMessage = functions.httpsCallable(`newRequest`);

Tài liệu về Firebase: https://firebase.google.com/docs/fifts/callable

Nếu bạn không thể khởi tạo SDK thì đây là bản chất từ ​​các đề xuất khác:


3
thực sự khi tôi sử dụng onCall func trên trình duyệt tôi đã gặp lỗi cors. Tôi có thể đặt tiêu đề costom trong yêu cầu này không?
Viktor Hardubej

4

Tìm thấy một cách để kích hoạt cors mà không cần nhập bất kỳ thư viện 'cors' nào. Nó cũng hoạt động với Typescriptvà thử nghiệm nó trong phiên bản chrome 81.0.

exports.createOrder = functions.https.onRequest((req, res) => {
// browsers like chrome need these headers to be present in response if the api is called from other than its base domain
  res.set("Access-Control-Allow-Origin", "*"); // you can also whitelist a specific domain like "http://127.0.0.1:4000"
  res.set("Access-Control-Allow-Headers", "Content-Type");

  // your code starts here

  //send response
  res.status(200).send();
});

3

Đối với những gì nó có giá trị tôi đã có cùng một vấn đề khi đi appvào onRequest. Tôi nhận ra vấn đề là một dấu gạch chéo trên url yêu cầu cho chức năng firebase. Express đang tìm kiếm '/'nhưng tôi không có dấu gạch chéo trên hàm [project-id].cloudfunctions.net/[function-name]. Lỗi CORS là âm tính giả. Khi tôi thêm dấu gạch chéo, tôi nhận được phản hồi mà tôi mong đợi.


cũng đảm bảo bạn thêm của bạn [project-id]vì đây là vấn đề tôi gặp phải
rút phích cắm

3

Chỉ có cách này hoạt động với tôi vì tôi có ủy quyền trong yêu cầu của tôi:

exports.hello = functions.https.onRequest((request, response) => {
response.set('Access-Control-Allow-Origin', '*');
response.set('Access-Control-Allow-Credentials', 'true'); // vital
if (request.method === 'OPTIONS') {
    // Send response to OPTIONS requests
    response.set('Access-Control-Allow-Methods', 'GET');
    response.set('Access-Control-Allow-Headers', 'Content-Type');
    response.set('Access-Control-Max-Age', '3600');
    response.status(204).send('');
} else {
    const params = request.body;
    const html = 'some html';
    response.send(html)
} )};

Các chức năng của đám mây google không cho phép nguồn gốc ký tự đại diện: cloud.google.com/fifts/docs/wr/ cấp
Corey Cole

3

Nếu bạn không / không thể sử dụng plugin cors, hãy gọi setCorsHeaders() hàm đầu tiên trong hàm xử lý cũng sẽ hoạt động.

Đồng thời sử dụng các hàm answerSuccess / Error khi trả lời lại.

const ALLOWED_ORIGINS = ["http://localhost:9090", "https://sub.example.com", "https://example.com"]


// Set CORS headers for preflight requests
function setCorsHeaders (req, res) {
  var originUrl = "http://localhost:9090"


  if(ALLOWED_ORIGINS.includes(req.headers.origin)){
    originUrl = req.headers.origin
  }

  res.set('Access-Control-Allow-Origin', originUrl);
  res.set('Access-Control-Allow-Credentials', 'true');

  if (req.method === 'OPTIONS') {
    // Send response to OPTIONS requests
    res.set('Access-Control-Allow-Methods', 'GET,POST','PUT','DELETE');
    res.set('Access-Control-Allow-Headers', 'Bearer, Content-Type');
    res.set('Access-Control-Max-Age', '3600');
    res.status(204).send('');
  }
}

function respondError (message, error, code, res) {
  var response = {
    message: message,
    error: error
  }
  res.status(code).end(JSON.stringify(response));
}


function respondSuccess (result, res) {
  var response = {
    message: "OK",
    result: result
  }
  res.status(200).end(JSON.stringify(response));
}

2

Nếu bạn đang thử nghiệm ứng dụng firebase cục bộ thì bạn cần trỏ các chức năng localhostthay vì đám mây. Theo mặc định, firebase servehoặc firebase emulators:starttrỏ các chức năng đến máy chủ thay vì localhost khi bạn sử dụng nó trên ứng dụng web của mình.

Thêm tập lệnh bên dưới vào đầu html sau tập lệnh init firebase:

 <script>
      firebase.functions().useFunctionsEmulator('http://localhost:5001')
 </script> 

Đảm bảo xóa đoạn mã này khi triển khai mã lên máy chủ.


2

Thay đổi truebằng cách "*"thực hiện thủ thuật cho tôi, vì vậy đây là cách nó diễn ra:

const cors = require('cors')({ origin: "*" })

Tôi đã thử cách tiếp cận này vì nói chung, đây là cách đặt tiêu đề phản hồi này:

'Access-Control-Allow-Origin', '*'

Xin lưu ý rằng điều này sẽ cho phép bất kỳ tên miền nào gọi điểm cuối của bạn do đó KHÔNG an toàn.

Ngoài ra, bạn có thể đọc thêm về các tài liệu: https://github.com/expressjs/cors


1

Nếu bạn không sử dụng Express hoặc chỉ đơn giản là muốn sử dụng CORS. Các mã sau đây sẽ giúp giải quyết

const cors = require('cors')({ origin: true, });   
exports.yourfunction = functions.https.onRequest((request, response) => {  
   return cors(request, response, () => {  
        // *Your code*
    });
});

0

Trong trường hợp của tôi, lỗi là do quyền truy cập giới hạn của hàm invoker. Vui lòng thêm allUsers vào đám mây chức năng invoker. Hãy nắm bắt liên kết . Vui lòng tham khảo bài viết để biết thêm


Vui lòng cung cấp một số giải thích về tài liệu được liên kết trong câu trả lời của bạn, tại sao nó có liên quan và như vậy
Firefly

0

Nếu không có giải pháp nào khác hoạt động, bạn có thể thử thêm địa chỉ bên dưới vào đầu cuộc gọi để bật CORS - redirect:

https://cors-anywhere.herokuapp.com/

Mã mẫu với yêu cầu AJAX của JQuery:

$.ajax({
   url: 'https://cors-anywhere.herokuapp.com/https://fir-agilan.web.app/gmail?mail=asd@gmail.com,
   type: 'GET'
});

0

Thêm phần kinh nghiệm của tôi. Tôi đã dành hàng giờ cố gắng để tìm ra lý do tại sao tôi có lỗi CORS.

Nó xảy ra rằng tôi đã đổi tên chức năng đám mây của mình (lần đầu tiên tôi đã thử sau khi nâng cấp lớn).

Vì vậy, khi ứng dụng firebase của tôi gọi hàm đám mây với tên không chính xác, nó sẽ gây ra lỗi 404 chứ không phải lỗi CORS.

Sửa tên hàm đám mây trong ứng dụng firebase của tôi đã khắc phục sự cố.

Tôi đã điền một báo cáo lỗi về vấn đề này tại đây https://firebase.google.com/support/troubledhooter/report/bugs

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.