FastApi跨域


一、概述

跨域資源共享(CORS) 是一種機制,它使用額外的 HTTP 頭來告訴瀏覽器  讓運行在一個 origin (domain) 上的Web應用被准許訪問來自不同源服務器上的指定的資源。當一個資源從與該資源本身所在的服務器不同的域、協議或端口請求一個資源時,資源會發起一個跨域 HTTP 請求

 

跨域資源共享標准新增了一組 HTTP 首部字段,允許服務器聲明哪些源站通過瀏覽器有權限訪問哪些資源。另外,規范要求,對那些可能對服務器數據產生副作用的 HTTP 請求方法(特別是 GET 以外的 HTTP 請求,或者搭配某些 MIME 類型的 POST 請求),瀏覽器必須首先使用 OPTIONS 方法發起一個預檢請求(preflight request),從而獲知服務端是否允許該跨域請求。服務器確認允許之后,才發起實際的 HTTP 請求。在預檢請求的返回中,服務器端也可以通知客戶端,是否需要攜帶身份憑證(包括 Cookies 和 HTTP 認證相關數據)。

 

FastAPI利用CORSMiddleware中間件來實現CORS。

為啥需要跨域處理,通常我們的API一般是給到前端去調用,但是前端可能使用域名和沒提供的API域名是不一樣,這就引發了瀏覽器同源策略問題,所以我們需要做跨域請求支持。

FastAPI支持跨域的話,可以通過添加中間的形式,不僅如此他還支持僅限於支持哪些域名進行跨域請求:

復制代碼
import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

origins = [
    "http://api.zwnsyw.com",
    "https://api.zwnsyw.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"}

if __name__ == '__main__':
    uvicorn.run(app='main:app', host="0.0.0.0", port=8000, reload=True, debug=True)
復制代碼

 

二、演示跨域

環境說明:

前端:

操作系統:centos 7.6

ip地址:192.168.31.35

運行軟件:nginx

 

后端:

操作系統:windows 10

ip地址:192.168.31.61

運行軟件:pycharm

 

請求api

登錄到前端服務器,安裝nginx,並啟動。

yum install -y nginx
nginx

訪問默認頁面

http://192.168.31.35/

 

 

 

測試頁面

登錄到前端服務器,默認的nginx頁面目錄為:/usr/share/nginx/html

新建一個測試文件

cd /usr/share/nginx/html
vi test.html

內容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<button id="api">請求接口</button>
<h4>結果</h4>
<div id="content"></div>
<script>
    $('#api').click(function () {
        $.ajax({  //發送ajax請求
            url: 'http://192.168.31.61:8000/',
            type: "get",
            data: {},
            success: function (arg) {
                //arg = JSON.parse(arg);
                console.log(arg);
                $('#content').text(arg.message)
                //return false;
            },
            error: function () {
                console.log("網絡請求錯誤!");
            }
        });
    });

</script>
</body>
</html>

 

 

訪問測試頁面

http://192.168.31.35/test.html

點擊請求接口按鈕,提示跨域。

 

為什么會出現跨域呢?因為同源策略。

同源策略是瀏覽器的一個安全功能,不同源的客戶端腳本在沒有明確授權的情況下,不能讀寫對方資源。所以192.168.31.35下的js腳本采用ajax讀取192.168.31.61里面的文件數據是會被拒絕的。

同源策略限制了從同一個源加載的文檔或腳本如何與來自另一個源的資源進行交互。這是一個用於隔離潛在惡意文件的重要安全機制。

 

三、解決跨域

一般解決跨域,是在后端完成的,設置允許跨域。

 

修改main.py,增加前端的url地址即可。

例如:前端服務器:http://43.226.150.147:39003          Fastapi服務器:http://43.226.150.147:8080      那么只需要將前端服務的地址或域名允許跨域就可以,也就是添加  http://43.226.150.147:39003  跨域

 

import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

"""↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓    Fastapi    ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓"""
# 前端頁面url
origins = [ "http://43.226.150.147:39003", "http://www.zwnsyw.com", "https://www.zwnsyw.com", ] # 后台api允許跨域
app.add_middleware( CORSMiddleware, allow_origins=origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], )


@app.get("/api")
async def home():
    return {"message": "Hello World"}


if __name__ == '__main__':
    uvicorn.run(app='main:app', host="0.0.0.0", port=8000, reload=True, debug=True)

 

再次點擊按鈕,結果就會顯示出來了。

四、使用CORSMiddleware

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頭信息列表。['*'] 表示允許所有頭信息。AcceptAccept-LanguageContent-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-urlencodedmultipart/form-datatext/plain

凡是不同時滿足上面兩個條件,就屬於非簡單請求。

瀏覽器對這兩種請求的處理,是不一樣的。

1、簡單請求

對於簡單請求,瀏覽器直接發出CORS請求。具體來說,就是在頭信息之中,增加一個Origin字段。

Origin字段用來說明,本次請求來自哪個源(協議 + 域名 + 端口)。服務器根據這個值,決定是否同意這次請求。 

 

在這種情況下,中間件會正常傳遞請求信息,但會在返回結果中包含恰當的CORS頭信息。

2、預檢請求

非簡單請求是那種對服務器有特殊要求的請求,比如請求方法是PUTDELETE,或者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

服務器收到"預檢"請求以后,檢查了OriginAccess-Control-Request-MethodAccess-Control-Request-Headers字段以后,確認是否允許跨源請求,就可以做出回應。

 

在這種情況下,中間件會攔截請求信息並且根據是否允許跨域請求返回不同的請求結果信息。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM