Files
012-kaopeilian/知识库/问题修复/CORS问题修复记录.md
111 998211c483 feat: 初始化考培练系统项目
- 从服务器拉取完整代码
- 按框架规范整理项目结构
- 配置 Drone CI 测试环境部署
- 包含后端(FastAPI)、前端(Vue3)、管理端

技术栈: Vue3 + TypeScript + FastAPI + MySQL
2026-01-24 19:33:28 +08:00

5.3 KiB
Raw Blame History

CORS跨域错误修复记录

日期2025-10-16
问题前端访问tasks API时出现CORS跨域错误
状态 已修复


错误信息

Access to XMLHttpRequest at 'http://localhost:8000/api/v1/manager/tasks/?status=ongoing' 
(redirected from 'http://localhost:8000/api/v1/manager/tasks?status=ongoing') 
from origin 'http://localhost:3001' has been blocked by CORS policy: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.

问题分析

根本原因

  1. 307重定向问题

    • 前端请求:/api/v1/manager/tasks (无斜杠)
    • FastAPI重定向到/api/v1/manager/tasks/ (有斜杠)
    • 状态码307 Temporary Redirect
  2. CORS预检失败

    • 浏览器发送CORS预检请求OPTIONS
    • 服务器返回307重定向
    • 浏览器不会在预检请求后跟随重定向
    • 导致CORS错误
  3. FastAPI默认行为

    • FastAPI默认会自动在URL末尾添加斜杠
    • 当路由定义为 @router.get("/") 且prefix="/manager/tasks"时
    • 实际路径是 /api/v1/manager/tasks/
    • 访问 /api/v1/manager/tasks 会触发307重定向

为什么CORS配置正确但仍然报错

虽然后端的CORS配置包含了 http://localhost:3001

CORS_ORIGINS: list[str] = Field(
    default=[
        "http://localhost:3000",
        "http://localhost:3001",  # ✅ 已配置
        "http://localhost:5173",
        ...
    ]
)

但是307重定向响应没有包含CORS头部导致浏览器阻止跟随重定向。


解决方案

修改内容

文件kaopeilian-backend/app/api/v1/tasks.py

修改1禁用自动重定向

# 修改前:
router = APIRouter(prefix="/manager/tasks", tags=["Tasks"])

# 修改后:
router = APIRouter(prefix="/manager/tasks", tags=["Tasks"], redirect_slashes=False)

修改2修改路由路径

# 修改前:
@router.get("/", response_model=...)
@router.post("/", response_model=...)

# 修改后:
@router.get("", response_model=...)  # 空字符串而非 "/"
@router.post("", response_model=...)

修改原理

  1. redirect_slashes=False

    • 告诉FastAPI不要自动添加/移除尾部斜杠
    • 避免触发307重定向
  2. 使用空字符串 ""

    • prefix="/manager/tasks" + @router.get("")
    • 最终路径:/api/v1/manager/tasks (精确匹配,无斜杠)
    • 避免歧义和重定向

验证结果

测试前(有重定向)

$ curl -I http://localhost:8000/api/v1/manager/tasks
HTTP/1.1 307 Temporary Redirect
location: http://localhost:8000/api/v1/manager/tasks/

测试后(无重定向)

$ curl -I http://localhost:8000/api/v1/manager/tasks
HTTP/1.1 401 Unauthorized  # 因为没有token这是预期行为

没有307重定向直接返回响应


相关知识点

1. CORS预检请求Preflight Request

浏览器在发送跨域请求前会先发送OPTIONS请求检查

  • 服务器是否允许该源Origin
  • 是否允许该HTTP方法
  • 是否允许该请求头

关键:预检请求不会跟随重定向!

2. FastAPI斜杠处理

FastAPI默认行为

  • /path/path/ 被视为不同的路径
  • 如果定义了 /path/,访问 /path 会重定向
  • 如果定义了 /path,访问 /path/ 也会重定向

3. 为什么其他API没问题

其他API可能

  • 使用了完整路径(如 /api/v1/exams/start
  • 前端调用时带了尾部斜杠
  • 路由定义使用了具体路径而非 "/"

最佳实践

1. API路由定义规范

推荐

# 对于列表/集合类资源
router = APIRouter(prefix="/manager/tasks", redirect_slashes=False)
@router.get("")    # 获取列表
@router.post("")   # 创建新项

# 对于具体资源
@router.get("/{task_id}")     # 获取详情
@router.put("/{task_id}")     # 更新
@router.delete("/{task_id}")  # 删除

避免

# 避免使用 "/" 作为路径,容易引起重定向
@router.get("/")
@router.post("/")

2. 前后端API路径约定

  • 后端定义什么路径,前端就用什么路径
  • 统一不使用尾部斜杠(推荐)
  • 或统一使用尾部斜杠
  • 避免混用

3. FastAPI Router配置

router = APIRouter(
    prefix="/api/path",
    tags=["Tag"],
    redirect_slashes=False  # 推荐添加,避免意外重定向
)

影响范围

修改的文件

  • kaopeilian-backend/app/api/v1/tasks.py

影响的API

  • GET /api/v1/manager/tasks - 获取任务列表
  • POST /api/v1/manager/tasks - 创建任务
  • GET /api/v1/manager/tasks/stats - 任务统计
  • GET /api/v1/manager/tasks/{id} - 任务详情
  • PUT /api/v1/manager/tasks/{id} - 更新任务
  • DELETE /api/v1/manager/tasks/{id} - 删除任务

测试确认

  • 后端服务正常启动
  • API不再返回307重定向
  • CORS配置生效
  • 前端可以正常调用

总结

问题FastAPI默认的斜杠重定向导致CORS预检失败

解决

  1. 添加 redirect_slashes=False 配置
  2. 使用空字符串 "" 而非 "/" 作为路由路径

经验

  • CORS问题不一定是CORS配置错误
  • 307重定向会破坏CORS预检流程
  • FastAPI的路由斜杠处理需要特别注意
  • API设计应避免歧义路径

状态 已修复,可以正常使用