使 Sanic 后端支持 CORS
1. 源端消除 Preflight
Preflight(预检请求)是指在跨源发出用户请求前,预先发出一个 OPTIONS 请求,查询服务端是否允许从此源站的请求。
Restful 规范是“罪魁祸首”。因为跨域 fetch
时,application/json
类型的 Content-Type
必然会触发 Preflight。
只有满足简单请求的 fetch
,才不会触发 Preflight:
- 请求方法为 GET/HEAD/POST
- 除浏览器自动添加的 header 外,只可以人为设置 Accept/Accept-Language/Content-Language/Content-Type/Range 头部字段
Content-Type
只可以取值text/plain
/multipart/form-data
/application/x-www-form-urlencoded
所以要解决常见的 restful 式的 Preflight,最简单的解决办法,就是去掉显式的 Content-Type
声明。浏览器会默认消息体格式为 text/plain
。
2. 后端允许 CORS
当请求头字段 Origin
标识的地址跟服务端地址不同时,即构成 CORS。如果服务端接受从此地址发出的请求,需要添加响应头 Access-Control-Allow-Origin
。
Access-Control-Allow-Origin
字段值可以是通配符 *
:
1 | Access-Control-Allow-Origin: * |
表示此资源对所有访问者开放。字段值也可以是某一个具体的地址,表示只限定此源的访问:
1 | Access-Control-Allow-Origin: https://foo.example |
具体到 Sanic,可以通过安装 sanic-ext 扩展实现对 CORS 的完整支持:
1 | pip install sanic-ext |
1 | from sanic_ext import Extend |
简单来说,扩展通过截听路由,为其添加对 OPTIONS 的响应;并动态添加 CORS 必需的响应头,以此实现了 CORS 支持。
回到 Restful 场景,或其它可以在源端避免 Preflight 的任何场景,sanic-ext 则不是必需。仅需在每个响应的头中加入 access-control-allow-origin
字段即可:
1 |
|
参考
- 跨源资源共享(CORS):https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS
- Cross-origin resource sharing (CORS):https://sanic.dev/en/guide/how-to/cors.html
- CORS protection:https://sanic.dev/en/plugins/sanic-ext/http/cors.html#basic-implementation