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

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

229 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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设计应避免歧义路径
---
**状态**:✅ 已修复,可以正常使用