Skip to content

FastAPI CORS 配置

问题描述

在使用 FastAPI 开发 Web 应用时,经常会遇到跨域资源共享 (CORS) 问题。当浏览器从不同域、协议或端口的网页发起请求时,出于安全考虑会阻止这些跨域请求。FastAPI 提供了内置的 CORSMiddleware 来解决这个问题,但有时配置可能不会按预期工作。

基本解决方案

FastAPI 通过 CORSMiddleware 提供 CORS 支持。以下是正确的配置方式:

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

app = FastAPI()

# 允许的源列表
origins = [
    "http://localhost:3000",  # React 开发服务器
    "http://localhost:8080",  # Vue 开发服务器
    # 添加其他需要允许的源
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,  # 允许的源列表
    allow_credentials=True,  # 是否允许携带 cookie
    allow_methods=["*"],     # 允许的 HTTP 方法
    allow_headers=["*"],     # 允许的请求头
)

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

配置参数详解

allow_origins

指定允许跨域请求的来源列表。对于开发环境,可以使用 ["*"] 允许所有来源,但在生产环境中应该明确指定允许的域名。

allow_credentials

指示是否允许浏览器在跨域请求中发送 cookies 和认证信息。

allow_methods

允许的 HTTP 方法列表,如 ["GET", "POST", "PUT", "DELETE"]

allow_headers

允许的请求头列表,可以使用 ["*"] 允许所有头信息。

其他可选参数

  • expose_headers: 允许浏览器访问的响应头列表
  • max_age: 预检请求的缓存时间(秒)

常见问题与解决方案

1. 本地文件访问的特殊情况

安全风险

当客户端从本地文件(如 file:// 协议)发起请求时,请求源会是 'null'。这种情况下需要特殊处理:

python
app.add_middleware(
    CORSMiddleware, 
    allow_origins=['null'],
    allow_credentials=True, 
    allow_methods=['*'], 
    allow_headers=['*']
)

请注意,这种配置有安全风险,不建议在生产环境使用。

2. 服务器端错误导致 CORS 问题

有时服务器端错误(如 Pydantic 验证失败或数据库查询错误)可能导致 CORS 头信息未能正确设置。确保服务器端代码没有隐藏的错误:

python
# 错误示例:缺少 await 关键字
@app.get("/error")
async def main():
    # 这将导致服务器错误,可能影响 CORS 设置
    ret = mongo_db.engine.find(Book, limit=10)  # 缺少 await
    return ret

3. 重复初始化 FastAPI 实例

确保没有在代码的其他地方重复创建 FastAPI 实例,这会导致 CORS 配置被覆盖:

python
app = FastAPI()
app.add_middleware(CORSMiddleware, ...)

# ... 其他代码 ...

# 错误:再次创建 FastAPI 实例会覆盖之前的配置
app = FastAPI()  # CORS 配置丢失

4. 需要暴露自定义响应头

如果前端需要访问自定义响应头,需要使用 expose_headers 参数:

python
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000"],
    expose_headers=["Custom-Header", "Another-Header"]
)

完整示例

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

app = FastAPI()

# 配置 CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=[
        "http://localhost:3000",
        "http://localhost:8080",
        "https://your-production-domain.com"
    ],
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    allow_headers=["*"],
    expose_headers=["Content-Range", "X-Total-Count"]
)

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

@app.get("/api/items")
async def get_items():
    return {"items": ["item1", "item2", "item3"]}

测试 CORS 配置

可以使用 curl 或浏览器开发者工具验证 CORS 配置是否生效:

bash
# 使用 curl 测试 OPTIONS 预检请求
curl -X OPTIONS http://localhost:8000/api/items \
  -H "Origin: http://localhost:3000" \
  -H "Access-Control-Request-Method: GET" \
  -H "Access-Control-Request-Headers: Content-Type" \
  -v

安全最佳实践

重要安全提示

  1. 在生产环境中避免使用 allow_origins=["*"]
  2. 明确指定允许的域名列表
  3. 根据需要最小化 allow_methodsallow_headers 的范围
  4. 定期审查和更新 CORS 配置

通过正确配置 FastAPI 的 CORS 中间件,您可以安全地处理跨域请求,同时确保应用程序的安全性。