Blog Cover Image

Inspire you to have New thinking, Walk out your unique Road.

[後端] 解決CORS跨域請求的研究筆記(Python FastAPI + Firebase/Firestore)

Posted onJul 7, 2023

由於最近在將我的命理服務的前端和後端串接,又遇到了 CORS 跨域問題,但我記得這個問題先前也有遇過,可是完全忘記之前怎麼解決,所以這次特地寫了一篇文章紀錄。

前言 & 什麼是 CORS (Cross-origin resource sharing)

我相信許多其他部落客或技術文章會寫得比我更詳細,這邊就簡短描述一下。

在提及 CORS 之前,先描述同源策略(Same-origin policy),由於資訊安全的關係,為防止網站內的資源請求(例如前端 call 後端的 API 取得資訊,或者前端網站的圖像、CSS 及一些資源需要使用外部請求時),必須是同源/同個域名/同個 domain,為防止駭客或其他有心人士假冒假的域名侵入你的服務。

但隨著科技的發達呢,現在的軟體服務很多會去使用到第三方或者外部的資源請求,所以就會有 CORS 跨域請求的出現。

  1. 我最現成的例子是 Jamstack,我將我的前端網站架在 Github,但後端的 API 我架在 Vercel 上,當前端使用 fetch 對後端的 API 請求時,出現了Access to Reqeust, ... has been blocked by CORS policy

這應該是蠻多技術人員會遇到的問題。

  1. 先前我的前端網站需要存取 Google Firestore & Firebase 資訊時,也遇到了 CORS 問題。

但本人非常的健忘,所以以至於這次遇到 CORS 問題時,又花了些時間找解決方法。

許多以前端為本的解決方法嘗試過了沒有成功,後來才想起是要去後端的部分加上 CORS,然後將前端的網域加入白名單,使前端請求能被允許傳入後端 API 中。

我查了很多關於後端的解決方式,但因為每個人的服務都不同,有的服務需要去 NGINX 修改設定,但我的是去後端 API 層加上 CORS 實作,所以本篇會以兩個我遇到的案例提供解決方法。

案例一: 前端 React.js with 後端 Python Fask API

當 React.js 實作的前端網站使用 fetch 送出 HTTPS 請求時,被後端 API 擋下產生 CORS 問題。

因此這邊的解決方式就是,我們在後端的 API 層實作 CORS,並將前端網域加入白名單,以下是實作程式碼:


# Import fastapi的套件
from fastapi import FastAPI

# Import fastapi的cors功能
from fastapi.middleware.cors import CORSMiddleware

# (1) Init 一個 app
app = FastAPI()

# (2) 將你想要allow請求的白名單放這
origins = [
    "http://localhost",
    "https://example.com"
]

# (3) Init CORS物件,並將設定及白名單加入app中
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# (4) 撰寫你的api route
@app.get("/")
def hello_word():
    return {"Hello": "World"}

案例二: React.js 前端 存取 Google Firestore or Firebase

在此案例為 React.js 前端網頁存取 Google 的資料庫(Firestore or Firebase),前端網頁的域名被 Google 擋掉。

而設定需要去 Google Cloud 的 Console 去做設定

先前往 Google Firebase Console,選取你的專案(此為 fancy-chatroom),然後確認有沒有 Authentication 在左邊的 Navbar。

如果沒有的話,需要進入左邊最下面的所有產品,然後創一個新的 Authentication

創好後,回到 Authentication -> Settings -> 授權網域 -> 新增網域,加入你希望能夠 allow 哪些網站的請求,加入完之後就不會有 CORS 的報錯了!

大家試試看吧!