作者:麥克煎蛋 出處:https://www.cnblogs.com/mazhiyong/ 轉載請保留這段聲明,謝謝!
跨域資源共享(CORS) 是一種機制,它使用額外的 HTTP 頭來告訴瀏覽器 讓運行在一個 origin (domain) 上的Web應用被准許訪問來自不同源服務器上的指定的資源。當一個資源從與該資源本身所在的服務器不同的域、協議或端口請求一個資源時,資源會發起一個跨域 HTTP 請求。
跨域資源共享標准新增了一組 HTTP 首部字段,允許服務器聲明哪些源站通過瀏覽器有權限訪問哪些資源。另外,規范要求,對那些可能對服務器數據產生副作用的 HTTP 請求方法(特別是 GET 以外的 HTTP 請求,或者搭配某些 MIME 類型的 POST 請求),瀏覽器必須首先使用 OPTIONS 方法發起一個預檢請求(preflight request),從而獲知服務端是否允許該跨域請求。服務器確認允許之后,才發起實際的 HTTP 請求。在預檢請求的返回中,服務器端也可以通知客戶端,是否需要攜帶身份憑證(包括 Cookies 和 HTTP 認證相關數據)。
FastAPI利用CORSMiddleware中間件來實現CORS。
一、使用CORSMiddleware
我們通過以下流程在FastAPI應用中使用CORSMiddleware。
1、導入CORSMiddleware。
2、創建允許的origins列表。
3、在應用中引入CORSMiddleware中間件。
如果后端支持我們也可以加入以下信息:
4、鑒權信息(Authorization headers, Cookies等)。
5、支持的HTTP方法(POST,GET,或者所有"*")。
6、支持的HTTP頭信息或者所有"*"。
from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware app = FastAPI() origins = [ "http://localhost.tiangolo.com", "https://localhost.tiangolo.com", "http://localhost", "http://localhost:8080", ] app.add_middleware( CORSMiddleware, allow_origins=origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.get("/") async def main(): return {"message": "Hello World"}
CORSMiddleware的參數默認值是受限制的,為了在跨域訪問中支持相應的功能,我們應當顯示指定具體參數的的信息。
CORSMiddleware支持參數信息如下:
1、allow_origins:允許跨域請求的域名列表,例如 ['https://example.org', 'https://www.example.org'] 或者 ['*']。
2、allow_origin_regex:允許跨域請求的域名正則表達式,例如 'https://.*\.example\.org'。
3、allow_methods:允許跨域請求的HTTP方法列表,默認為['GET'],['*'] 表示允許所有HTTP方法。
4、allow_headers:跨域請求支持的HTTP頭信息列表。['*'] 表示允許所有頭信息。Accept, Accept-Language, Content-Language 和 Content-Type頭信息默認全都支持。
5、allow_credentials:表示在跨域請求時是否支持cookie,默認為False。
6、expose_headers:表示對瀏覽器可見的返回結果頭信息,默認為[]。
7、max_age:瀏覽器緩存CORS返回結果的最大時長,默認為600(單位秒)。
二、請求種類
瀏覽器將CORS請求分成兩類:簡單請求(Simple requests)和非簡單請求,也叫預檢請求(CORS preflight requests)。
只要同時滿足以下兩大條件,就屬於簡單請求。
(1) 請求方法是以下三種方法之一:
- HEAD
- GET
- POST
(2)HTTP的頭信息不超出以下幾種字段:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只限於三個值
application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不同時滿足上面兩個條件,就屬於非簡單請求。
瀏覽器對這兩種請求的處理,是不一樣的。
1、簡單請求
對於簡單請求,瀏覽器直接發出CORS請求。具體來說,就是在頭信息之中,增加一個Origin字段。
Origin字段用來說明,本次請求來自哪個源(協議 + 域名 + 端口)。服務器根據這個值,決定是否同意這次請求。
在這種情況下,中間件會正常傳遞請求信息,但會在返回結果中包含恰當的CORS頭信息。
2、預檢請求
非簡單請求是那種對服務器有特殊要求的請求,比如請求方法是PUT或DELETE,或者Content-Type字段的類型是application/json。
非簡單請求的CORS請求,會在正式通信之前,增加一次HTTP查詢請求,稱為"預檢"請求(preflight)。
瀏覽器先詢問服務器,當前網頁所在的域名是否在服務器的許可名單之中,以及可以使用哪些HTTP方法和頭信息字段。只有得到肯定答復,瀏覽器才會發出正式的請求,否則就報錯。
"預檢"請求用的請求方法是OPTIONS,表示這個請求是用來詢問的。頭信息里面,關鍵字段是Origin,表示請求來自哪個源。
除了Origin字段,"預檢"請求的頭信息包括兩個特殊字段。
(1)Access-Control-Request-Method
該字段是必須的,用來列出瀏覽器的CORS請求會用到哪些HTTP方法,上例是PUT。
(2)Access-Control-Request-Headers
該字段是一個逗號分隔的字符串,指定瀏覽器CORS請求會額外發送的頭信息字段,上例是X-Custom-Header。
服務器收到"預檢"請求以后,檢查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,確認是否允許跨源請求,就可以做出回應。
在這種情況下,中間件會攔截請求信息並且根據是否允許跨域請求返回不同的請求結果信息。
關於CORS的更多信息,可訪問Mozilla CORS documentation。
參考文章:
https://www.cnblogs.com/knowledgesea/p/6808411.html
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
