FastAPI 中间件(三) 跨域资源共享中间件

作者:麦克煎蛋   出处: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-LanguageContent-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字段以后,确认是否允许跨源请求,就可以做出回应。

 

在这种情况下,中间件会拦截请求信息并且根据是否允许跨域请求返回不同的请求结果信息。

 

关于CORS的更多信息,可访问Mozilla CORS documentation

 

参考文章:

https://www.cnblogs.com/knowledgesea/p/6808411.html

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

posted on 2020-06-04 18:22  麦克煎蛋  阅读(3140)  评论(1编辑  收藏  举报