一、什么是跨域问题
跨域资源共享(CORS)是浏览器的一种安全机制。当一个在浏览器中运行的前端应用,其 JavaScript 代码尝试与不同源的后端通信时,就会产生跨域请求。
什么是"源"?
源由三部分组成:
-
协议(http / https)
-
域名 (myapp.com / localhost)
-
端口(80 / 443 / 8080)
只要协议、域名、端口中任意一个不同,就属于不同源。例如,即使都在 localhost 上,http://localhost:5173 和 http://localhost:8000 也是不同的源。
| 前端 | 后端 | 是否跨域 |
|---|---|---|
| http://localhost:5173 | http://localhost:8000 | ✅ 跨域 |
| http://example.com | http://api.example.com | ✅ 跨域 |
| http://example.com | http://example.com | ❌ 不跨域 |
二、跨域问题长什么样?
假设前端 Vue 应用运行在 http://localhost:5173,后端 FastAPI 运行在 http://127.0.0.1:8000。当前端向后端发起请求时,浏览器会拦截并报错:
Access to XMLHttpRequest at 'http://127.0.0.1:8000/api/news'
from origin 'http://localhost:5173'
has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
这是浏览器同源策略在起作用------它默认阻止不同源之间的资源访问。如果没有正确配置 CORS,前端应用将无法调用后端 API。
三、FastAPI 如何解决跨域问题
FastAPI 内置了 CORSMiddleware 中间件,只需几步配置即可解决跨域问题。
第一步:导入 CORSMiddleware
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
第二步:配置允许的源
app = FastAPI()
# 配置允许跨域访问的源列表
origins = [
"http://localhost",
"http://localhost:5173", # Vue 开发服务器默认端口
"http://localhost:8080",
"https://your-production-domain.com",
]
第三步:添加 CORS 中间件
app.add_middleware(
CORSMiddleware,
allow_origins=origins, # 允许的源
allow_credentials=True, # 允许携带 Cookie
allow_methods=["*"], # 允许所有 HTTP 方法
allow_headers=["*"], # 允许所有请求头
)
完成以上配置后,前端即可正常调用后端接口。
四、CORSMiddleware 核心参数详解
| 参数 | 说明 | 示例 |
|---|---|---|
allow_origins |
允许跨域请求的源列表 | ["http://localhost:5173"] 或 ["*"] |
allow_origin_regex |
使用正则表达式匹配允许的源 | "https://.*\.example\.com" |
allow_methods |
允许的 HTTP 方法 | ["GET", "POST", "PUT", "DELETE"] 或 ["*"] |
allow_headers |
允许的请求头 | ["Content-Type", "Authorization"] 或 ["*"] |
allow_credentials |
是否允许跨域请求携带凭证(Cookie、Authorization 头等) | True 或 False |
expose_headers |
允许浏览器访问的响应头 | ["X-Custom-Header"] |
max_age |
浏览器缓存预检请求结果的时间(秒) | 3600 |
注意 :
CORSMiddleware的默认参数非常保守,必须显式配置才能允许跨域请求。
五、allow_origins=["*"] 的坑
允许所有源看似最简单,但有重要限制:
五、allow_origins=["*"] 的坑
允许所有源看似最简单,但有重要限制:
原因 :当 allow_credentials=True 时,allow_origins 不能是 ["*"],必须指定具体的源(冲突是有条件的 ------只有当请求实际携带凭证时,浏览器才会拒绝。)
# ✅ 正确做法:明确列出允许的源
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173", "https://example.com"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
六、开发环境 vs 生产环境配置
开发环境(宽松配置)
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173", "http://localhost:3000", "http://127.0.0.1:5173"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
生产环境(严格配置)
生产环境应只允许可信的源:
app.add_middleware(
CORSMiddleware,
allow_origins=[
"https://example.com",
"https://www.example.com",
],
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "DELETE"],
allow_headers=["Content-Type", "Authorization"],
max_age=3600, # 缓存预检请求 1 小时
)
最佳实践:将允许的源放在环境变量中,避免硬编码:
import os
ALLOWED_ORIGINS = os.getenv("ALLOWED_ORIGINS", "").split(",")
app.add_middleware(
CORSMiddleware,
allow_origins=ALLOWED_ORIGINS,
# ...
)
七、完整代码示例
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# 配置 CORS
origins = [
"http://localhost:5173", # Vue 开发环境
"http://localhost:3000", # React 开发环境
"https://your-domain.com", # 生产环境
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/")
async def root():
return {"message": "Hello World"}
八、总结
| 步骤 | 操作 |
|---|---|
| 1 | from fastapi.middleware.cors import CORSMiddleware |
| 2 | 定义 origins 列表,包含允许的前端源 |
| 3 | 调用 app.add_middleware(CORSMiddleware, ...) 配置参数 |
| 4 | 特别注意:allow_credentials=True 时不能用 allow_origins=["*"] |
| 5 | 生产环境只允许可信源,使用环境变量管理 |
配置完 CORS 中间件后,浏览器会收到后端返回的 Access-Control-Allow-Origin 响应头,从而允许跨域请求正常进行。