# 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`: ```python 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:禁用自动重定向 ```python # 修改前: router = APIRouter(prefix="/manager/tasks", tags=["Tasks"]) # 修改后: router = APIRouter(prefix="/manager/tasks", tags=["Tasks"], redirect_slashes=False) ``` #### 修改2:修改路由路径 ```python # 修改前: @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` (精确匹配,无斜杠) - 避免歧义和重定向 --- ## 验证结果 ### 测试前(有重定向) ```bash $ curl -I http://localhost:8000/api/v1/manager/tasks HTTP/1.1 307 Temporary Redirect location: http://localhost:8000/api/v1/manager/tasks/ ``` ### 测试后(无重定向) ```bash $ 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路由定义规范 **推荐**: ```python # 对于列表/集合类资源 router = APIRouter(prefix="/manager/tasks", redirect_slashes=False) @router.get("") # 获取列表 @router.post("") # 创建新项 # 对于具体资源 @router.get("/{task_id}") # 获取详情 @router.put("/{task_id}") # 更新 @router.delete("/{task_id}") # 删除 ``` **避免**: ```python # 避免使用 "/" 作为路径,容易引起重定向 @router.get("/") @router.post("/") ``` ### 2. 前后端API路径约定 - 后端定义什么路径,前端就用什么路径 - 统一不使用尾部斜杠(推荐) - 或统一使用尾部斜杠 - **避免混用** ### 3. FastAPI Router配置 ```python 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设计应避免歧义路径 --- **状态**:✅ 已修复,可以正常使用